Merge pull request #63 from SCS-ASSE-FS21-Group1/auctionhouse-websub

Auctionhouse websub
This commit is contained in:
reynisson
2021-11-14 22:16:15 +01:00
committed by GitHub
11 changed files with 332 additions and 6 deletions

View File

@@ -58,6 +58,17 @@
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>
<build>

View File

@@ -8,6 +8,7 @@ import ch.unisg.tapas.common.ConfigProperties;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -32,18 +33,16 @@ public class TapasAuctionHouseApplication {
SpringApplication tapasAuctioneerApp = new SpringApplication(TapasAuctionHouseApplication.class);
// We will use these bootstrap methods in Week 6:
// bootstrapMarketplaceWithWebSub();
bootstrapMarketplaceWithWebSub();
bootstrapMarketplaceWithMqtt();
tapasAuctioneerApp.run(args);
}
/**
* Discovers auction houses and subscribes to WebSub notifications
*/
private static void bootstrapMarketplaceWithWebSub() {
List<String> auctionHouseEndpoints = discoverAuctionHouseEndpoints();
LOGGER.info("Found auction house endpoints: " + auctionHouseEndpoints);
WebSubSubscriber subscriber = new WebSubSubscriber();

View File

@@ -1,6 +1,15 @@
package ch.unisg.tapas.auctionhouse.adapter.common.clients;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.JSONObject;
import org.springframework.http.HttpStatus;
/**
* Subscribes to the WebSub hubs of auction houses discovered at run time. This class is instantiated
@@ -9,7 +18,24 @@ import java.net.URI;
*/
public class WebSubSubscriber {
// TODO get this somehow from properties file. But on clue how to do this with static variables
static String WEBSUB_HUB_ENDPOINT = "http://localhost:3000";
static String AUCTION_HOUSE_ENDPOINT = "http://localhost:8086";
Logger logger = Logger.getLogger(WebSubSubscriber.class.getName());
public void subscribeToAuctionHouseEndpoint(URI endpoint) {
// TODO decide with other groups about auction house endpoint uri to discover websub topics
// and replace the hardcoded one with it
String topic = discoverWebSubTopic("http://localhost:3100/websub");
if (topic == null) {
return;
}
subscribeToWebSub(topic);
// Shoudl be done :D
// TODO Subscribe to the auction house endpoint via WebSub:
// 1. Send a request to the auction house in order to discover the WebSub hub to subscribe to.
// The request URI should depend on the design of the Auction House HTTP API.
@@ -25,4 +51,61 @@ public class WebSubSubscriber {
// - W3C WebSub Recommendation: https://www.w3.org/TR/websub/
// - the implementation notes of the WebSub hub you are using to distribute events
}
private String discoverWebSubTopic(String endpoint) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Content-Type", "application/json")
.GET()
.build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == HttpStatus.OK.value()) {
// TODO decide with other groups about response structure and replace the hardcoded
// uri with response uri
JSONObject jsonObject = new JSONObject(response.body());
System.out.println(jsonObject);
return jsonObject.getString("topic");
} else {
logger.log(Level.SEVERE, "Could not find a websub uri");
}
} catch (InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
Thread.currentThread().interrupt();
} catch (IOException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
return null;
}
private void subscribeToWebSub(String topic) {
HttpClient client = HttpClient.newHttpClient();
String body = new JSONObject()
.put("hub.callback", AUCTION_HOUSE_ENDPOINT + "/auction-started")
.put("hub.mode", "subscribe")
.put("hub.topic", topic)
.put("hub.ws", false)
.toString();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(WEBSUB_HUB_ENDPOINT))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
try {
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
Thread.currentThread().interrupt();
} catch (IOException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
}
}

View File

@@ -1,6 +1,22 @@
package ch.unisg.tapas.auctionhouse.adapter.in.messaging.websub;
import ch.unisg.tapas.auctionhouse.adapter.common.formats.AuctionJsonRepresentation;
import ch.unisg.tapas.auctionhouse.application.handler.AuctionStartedHandler;
import ch.unisg.tapas.auctionhouse.application.port.in.AuctionStartedEvent;
import ch.unisg.tapas.auctionhouse.domain.Auction;
import ch.unisg.tapas.auctionhouse.domain.Auction.AuctionDeadline;
import ch.unisg.tapas.auctionhouse.domain.Auction.AuctionHouseUri;
import ch.unisg.tapas.auctionhouse.domain.Auction.AuctionId;
import ch.unisg.tapas.auctionhouse.domain.Auction.AuctionedTaskType;
import ch.unisg.tapas.auctionhouse.domain.Auction.AuctionedTaskUri;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import org.json.JSONArray;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/**
@@ -13,6 +29,25 @@ public class AuctionStartedEventListenerWebSubAdapter {
public AuctionStartedEventListenerWebSubAdapter(AuctionStartedHandler auctionStartedHandler) {
this.auctionStartedHandler = auctionStartedHandler;
}
/**
* Controller which listens to auction-started callbacks
* @return 200 OK
* @throws URISyntaxException
**/
@PostMapping(path = "/auction-started")
public ResponseEntity<Void> handleExecutorAddedEvent(@RequestBody Collection<AuctionJsonRepresentation> payload) throws URISyntaxException {
//TODO
for (AuctionJsonRepresentation auction : payload) {
auctionStartedHandler.handleAuctionStartedEvent(
new AuctionStartedEvent(
new Auction(new AuctionId(auction.getAuctionId()),
new AuctionHouseUri(new URI(auction.getAuctionHouseUri())),
new AuctionedTaskUri(new URI(auction.getTaskUri())),
new AuctionedTaskType(auction.getTaskType()),
new AuctionDeadline(auction.getDeadline()))
));
}
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,33 @@
package ch.unisg.tapas.auctionhouse.adapter.in.messaging.websub;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/**
* This class validates the subscription intent from the websub hub
*/
@RestController
public class ValidateIntentWebSubAdapter {
@Value("${application.environment}")
private String environment;
@GetMapping(path = "/auction-started")
public ResponseEntity<String> validateIntent(@RequestParam("hub.challenge") String challenge) {
// Different implementation depending on local development or production
if (environment.equalsIgnoreCase("development")) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
String body = new JSONObject()
.put("hub.challenge", challenge)
.toString();
return new ResponseEntity<>(body, headers, HttpStatus.OK);
} else {
return new ResponseEntity<>(challenge, HttpStatus.OK);
}
}
}

View File

@@ -4,12 +4,16 @@ import ch.unisg.tapas.auctionhouse.application.port.out.AuctionStartedEventPort;
import ch.unisg.tapas.auctionhouse.domain.Auction;
import ch.unisg.tapas.auctionhouse.domain.AuctionStartedEvent;
import ch.unisg.tapas.common.ConfigProperties;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
@@ -17,6 +21,8 @@ import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
@@ -29,8 +35,38 @@ public class PublishAuctionStartedEventWebSubAdapter implements AuctionStartedEv
@Autowired
private ConfigProperties config;
@Value("${auctionhouse.uri}")
private String auctionHouseUri;
@Value("${websub.hub.uri}")
private String webSubHubUri;
Logger logger = Logger.getLogger(PublishAuctionStartedEventWebSubAdapter.class.getName());
@Override
public void publishAuctionStartedEvent(AuctionStartedEvent event) {
// TODO
HttpClient client = HttpClient.newHttpClient();
String body = new JSONObject()
.put("hub.url", auctionHouseUri + "/auctions")
.put("hub.mode", "publish")
.toString();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(webSubHubUri))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
try {
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
Thread.currentThread().interrupt();
} catch (IOException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
}
}

View File

@@ -7,5 +7,7 @@ group=tapas-group-tutors
auction.house.uri=https://tapas-auction-house.86-119-34-23.nip.io/
tasks.list.uri=https://tapas-tasks.86-119-34-23.nip.io/
application.environment=development
auctionhouse.uri=http://localhost:8086
websub.hub.uri=http://localhost:3000
mqtt.broker.uri=tcp://localhost:1883