8 Commits

Author SHA1 Message Date
32bf461026 Merge pull request #98 from SCS-ASSE-FS21-Group1/discovery-web-controller
added the necessary classes for the discovery web controller
2021-12-06 03:34:30 +01:00
560f1ff34b added ahCrawler and finished discovery endpoint 2021-12-06 03:32:15 +01:00
reynisson
ec26b84dc9 Added a discover adapter and changed the domain object a bit 2021-12-05 22:41:52 +01:00
julius.lautz
0b89e88905 added the necessary classes for the discovery web controller 2021-12-04 15:16:29 +01:00
reynisson
9f42fcfcc4 Updated ADR on event driven microservices. 2021-12-02 23:39:21 +01:00
reynisson
96e323a705 Merge remote-tracking branch 'origin/dev' into dev 2021-12-02 23:32:01 +01:00
reynisson
de2f6cf0c4 Updated ADRs 2021-12-02 23:31:50 +01:00
67a952003d updated workflow 2021-12-02 22:48:54 +01:00
24 changed files with 1795 additions and 202 deletions

View File

@@ -0,0 +1,21 @@
# 2. Seperate service for Executor Pool
Date: 2021-11-21
## Status
Accepted
## Context
The Executor Pool has to keep track of which Executors are online and what task types they can execute. The Roster keeps track of tasks that need to be executed and assigns Executors to tasks. The Executor Pool functionalty could be implemented in a seperate service or as a part of the Roster.
## Decision
The executor pool will be implemented as a seperate service. (TODO decision might change. Need to reevaluate)
TODO explain why.
## Consequences
TODO

View File

@@ -1,23 +0,0 @@
# 2. Seperate service for Executors and Executor Pool
Date: 2021-11-21
## Status
Accepted
## Context
The executor pool has a complete list of all executors and knows if they are available or not, executors can execute tasks that match their type. The executors can therefore be part of the executor pool service, or each executor is a standalone service, as well as the executor pool.
## Decision
We will use a separate microservice for each executor and one service for the executor pool.
Having the executor pool and the executors as separate services would increase fault tolerance. If the executor pool goes down, the executors would stay online and execute their tasks without being affected by the executor pools outage. Likewise, if an executor goes down it does not impact other executors or the executor pool.
Different executors can have different execution times and a different load. This means the executors scale differently. Thus, we need a separate service for each executor.
Executors of different kinds will also scale differently than the executor pool and new executors of new types might be added at some point, further increasing the need for separate services to guarantee scalability and evolvability.
New executors will be added/removed during runtime. Therefore, we need a high extensibility.
## Consequences
Executors will be added/removed quite frequently, making the deployment of the system easier and less risk-prone if each executor is a separate service, also separated from the executor pool, which just keeps track of the executors and their status. However, having these separate services, the complexity might increase, and the testability of the system will decrease.

View File

@@ -6,7 +6,7 @@ Date: 2021-11-21
Proposed
Supercedes [5. Event driven communication](0005-event-driven-communication.md)
Supercedes [5. Event driven communication](0005-event-driven-communication.md) TODO Fix this. Should only supercede it if this has been accepted. This should also subercede 0013 - Microservice Architecture if accepted.
## Context

View File

@@ -0,0 +1,27 @@
# 12. seperate service for each executor
Date: 2021-11-21
## Status
Accepted
## Context
Executors must receive tasks of different types and execute them. The executors could either all be implemented within one service or as multiple services, one for each type of executor.
## Decision
We will have a seperate service for each type of executor.
Firstly, execution time differs significantly between task types. Therefore, having seperate services will allow the executos to scale differently based on their tasks' specific needs.
Secondly, the systems functioning should not be disrupted in case an Executor fails. Having each type of executor in a seperate service will increase fault tolerance in this regard.
Lastly, extensibilty is one of the systems most important non-functional requirement and providers of executors need to be able to easily add executors to the executor pool. These factors are also positively impacted by having seperate services.
There should not be any shared data between the executors. Additionally, there should be no flow of information between them. Thus, there should be no issues due to workflow and data concerns due to this decision.
## Consequences
Executors share a lot of functionality when it comes to connecting to the rest of the system. Therefore, this decision means that we will either have to duplicate the code that implements the common functionality, or we have to have a way to share the code (e.g. through a common library)

View File

@@ -0,0 +1,23 @@
# 13. microservice architecture
Date: 2021-12-02
## Status
Accepted
## Context
The system is made up of five distinct bounded contexts, namely the Task Domain, the Roster Domain, the Executor Pool Domain, the Executor Domain, and the Auction Domain. The way that these bounded contexts function together to fulfil the system requirements can be based on many different architectures. (Feedback needed. Should we name specific 'next-best' alternative architectures to compare, or just leave it as is since technically all architectures were considered)
## Decision
The system will follow the Microservice architecture.
Scalability and fault tolerance are two of the systems top 3 -ilities. Moreover, elasticity and evolvability are two of the systems other main -ilities. These are all non-functional requirements that the Microservice architecture excels at.
We do not expect to have a single monolithic database, so this is not a concern.
## Consequences
There is a considerable amount of communication between bounded contexts. This could cause responsiveness and performance issues due to added latency. This could therefore mean we would need to use asynchronous REST calls or publish-subscribe communication to mitigate these issues as much of the communication does not have to be synchronous.

View File

@@ -0,0 +1,19 @@
# 14. data ownership
Date: 2021-12-02
## Status
Accepted
## Context
The issue motivating this decision, and any context that influences or constrains the decision.
## Decision
The change that we're proposing or have agreed to implement.
## Consequences
What becomes easier or more difficult to do and any risks introduced by the change that will need to be mitigated.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 817 KiB

After

Width:  |  Height:  |  Size: 2.0 MiB

1
mocks/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules/

View File

@@ -0,0 +1,35 @@
// Require the framework and instantiate it
const fastify = require("fastify")({ logger: true });
// Declare a route
fastify.get("/discovery/", async (request, reply) => {
return {
auctionHouseInfo: [
{
auctionHouseURI: "http://localhost:3501",
webSubURI: "http://example.org",
taskTypes: ["COMPUTATION", "RANDOMTEXT"],
timeStamp: "2021-12-24 12:00:00",
groupName: "Group3",
},
{
auctionHouseURI: "http://localhost:3502",
webSubURI: "http://facemash.com",
taskTypes: ["BIGROBOT"],
timeStamp: "2021-12-24 12:00:00",
groupName: "Group2",
},
],
};
});
// Run the server!
const start = async () => {
try {
await fastify.listen(3501);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();

View File

@@ -0,0 +1,35 @@
// Require the framework and instantiate it
const fastify = require("fastify")({ logger: true });
// Declare a route
fastify.get("/discovery/", async (request, reply) => {
return {
auctionHouseInfo: [
{
auctionHouseURI: "http://localhost:3502",
webSubURI: "http://example.org",
taskTypes: ["COMPUTATION", "RANDOMTEXT"],
timeStamp: "2021-12-24 12:00:00",
groupName: "Group3",
},
{
auctionHouseURI: "http://localhost:3501",
webSubURI: "http://facemash.com",
taskTypes: ["BIGROBOT"],
timeStamp: "2021-12-26 12:00:00",
groupName: "GroupHAHAHA222",
},
],
};
});
// Run the server!
const start = async () => {
try {
await fastify.listen(3502);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();

View File

@@ -0,0 +1,35 @@
// Require the framework and instantiate it
const fastify = require("fastify")({ logger: true });
// Declare a route
fastify.get("/discovery/", async (request, reply) => {
return {
auctionHouseInfo: [
{
auctionHouseURI: "http://localhost:3500",
webSubURI: "http://example.org",
taskTypes: ["COMPUTATION", "RANDOMTEXT"],
timeStamp: "2021-12-24 12:00:00",
groupName: "Group3",
},
{
auctionHouseURI: "http://localhost:3501",
webSubURI: "http://facemash.com",
taskTypes: ["BIGROBOT"],
timeStamp: "2021-12-24 12:00:00",
groupName: "Group2",
},
],
};
});
// Run the server!
const start = async () => {
try {
await fastify.listen(3500);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();

5
mocks/package.json Normal file
View File

@@ -0,0 +1,5 @@
{
"dependencies": {
"fastify": "^3.24.1"
}
}

322
mocks/yarn.lock Normal file
View File

@@ -0,0 +1,322 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@fastify/ajv-compiler@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz#5ce80b1fc8bebffc8c5ba428d5e392d0f9ed10a1"
integrity sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg==
dependencies:
ajv "^6.12.6"
abstract-logging@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839"
integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==
ajv@^6.11.0, ajv@^6.12.6:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ajv@^8.1.0:
version "8.8.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb"
integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==
dependencies:
fast-deep-equal "^3.1.1"
json-schema-traverse "^1.0.0"
require-from-string "^2.0.2"
uri-js "^4.2.2"
archy@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=
atomic-sleep@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b"
integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==
avvio@^7.1.2:
version "7.2.2"
resolved "https://registry.yarnpkg.com/avvio/-/avvio-7.2.2.tgz#58e00e7968870026cd7b7d4f689d596db629e251"
integrity sha512-XW2CMCmZaCmCCsIaJaLKxAzPwF37fXi1KGxNOvedOpeisLdmxZnblGc3hpHWYnlP+KOUxZsazh43WXNHgXpbqw==
dependencies:
archy "^1.0.0"
debug "^4.0.0"
fastq "^1.6.1"
queue-microtask "^1.1.2"
cookie@^0.4.0:
version "0.4.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
debug@^4.0.0:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
dependencies:
ms "2.1.2"
deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
fast-decode-uri-component@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543"
integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-json-stringify@^2.5.2:
version "2.7.12"
resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-2.7.12.tgz#5bb7941695b52f545191bc396396230633f43592"
integrity sha512-4hjwZDPmgj/ZUKXhEWovGPciE/5mWtAIQQxN+2VBDFun7DRTk2oOItbu9ZZp6kqj+eZ/u7z+dgBgM74cfGRnBQ==
dependencies:
ajv "^6.11.0"
deepmerge "^4.2.2"
rfdc "^1.2.0"
string-similarity "^4.0.1"
fast-redact@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.0.2.tgz#c940ba7162dde3aeeefc522926ae8c5231412904"
integrity sha512-YN+CYfCVRVMUZOUPeinHNKgytM1wPI/C/UCLEi56EsY2dwwvI00kIJHJoI7pMVqGoMew8SMZ2SSfHKHULHXDsg==
fast-safe-stringify@^2.0.8:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
fastify-error@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/fastify-error/-/fastify-error-0.3.1.tgz#8eb993e15e3cf57f0357fc452af9290f1c1278d2"
integrity sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ==
fastify-warning@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f"
integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw==
fastify@^3.24.1:
version "3.24.1"
resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.24.1.tgz#979d34e096f40b7a90e90733efbbdae81623034e"
integrity sha512-ZL0V6u37d65tAY8lMwVMFtFvnEeJcG80QBNSdChqCm4i4x+is/38OU14gzJuRXhpenTL+pTJzNcu5Kn1ouzM3Q==
dependencies:
"@fastify/ajv-compiler" "^1.0.0"
abstract-logging "^2.0.0"
avvio "^7.1.2"
fast-json-stringify "^2.5.2"
fastify-error "^0.3.0"
fastify-warning "^0.2.0"
find-my-way "^4.1.0"
flatstr "^1.0.12"
light-my-request "^4.2.0"
pino "^6.13.0"
proxy-addr "^2.0.7"
rfdc "^1.1.4"
secure-json-parse "^2.0.0"
semver "^7.3.2"
tiny-lru "^7.0.0"
fastq@^1.6.1:
version "1.13.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
dependencies:
reusify "^1.0.4"
find-my-way@^4.1.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-4.4.0.tgz#e4a115031d1c5c538d028d06b666e2174462bc07"
integrity sha512-hpntHvK0iOHp3pqWRRUEzioar4tp8euBD8DkPG3VauOriZLgwGZLTNp6yZSrdctJ8RCDS7zhZSR2V+yOaBbNow==
dependencies:
fast-decode-uri-component "^1.0.1"
fast-deep-equal "^3.1.3"
safe-regex2 "^2.0.0"
semver-store "^0.3.0"
flatstr@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.12.tgz#c2ba6a08173edbb6c9640e3055b95e287ceb5931"
integrity sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==
forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema-traverse@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
light-my-request@^4.2.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.7.0.tgz#5bacd17fa0eaf96fe5eed1682c5e0d361953cf46"
integrity sha512-LTa8YZp3K2AUpqUnwwKajoIHcsKOBnzwJNQSrk7unziPwo6CjOYjyO0F9wfkxFvP+nBsCGe3eMPnedVgIIgdAw==
dependencies:
ajv "^8.1.0"
cookie "^0.4.0"
fastify-warning "^0.2.0"
set-cookie-parser "^2.4.1"
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
pino-std-serializers@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz#b56487c402d882eb96cd67c257868016b61ad671"
integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==
pino@^6.13.0:
version "6.13.3"
resolved "https://registry.yarnpkg.com/pino/-/pino-6.13.3.tgz#60b93bcda1541f92fb37b3f2be0a25cf1d05b6fe"
integrity sha512-tJy6qVgkh9MwNgqX1/oYi3ehfl2Y9H0uHyEEMsBe74KinESIjdMrMQDWpcZPpPicg3VV35d/GLQZmo4QgU2Xkg==
dependencies:
fast-redact "^3.0.0"
fast-safe-stringify "^2.0.8"
fastify-warning "^0.2.0"
flatstr "^1.0.12"
pino-std-serializers "^3.1.0"
quick-format-unescaped "^4.0.3"
sonic-boom "^1.0.2"
proxy-addr@^2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
dependencies:
forwarded "0.2.0"
ipaddr.js "1.9.1"
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
queue-microtask@^1.1.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
quick-format-unescaped@^4.0.3:
version "4.0.4"
resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7"
integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==
require-from-string@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
ret@~0.2.0:
version "0.2.2"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.2.2.tgz#b6861782a1f4762dce43402a71eb7a283f44573c"
integrity sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==
reusify@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rfdc@^1.1.4, rfdc@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
safe-regex2@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-2.0.0.tgz#b287524c397c7a2994470367e0185e1916b1f5b9"
integrity sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==
dependencies:
ret "~0.2.0"
secure-json-parse@^2.0.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.4.0.tgz#5aaeaaef85c7a417f76271a4f5b0cc3315ddca85"
integrity sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg==
semver-store@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/semver-store/-/semver-store-0.3.0.tgz#ce602ff07df37080ec9f4fb40b29576547befbe9"
integrity sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==
semver@^7.3.2:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
dependencies:
lru-cache "^6.0.0"
set-cookie-parser@^2.4.1:
version "2.4.8"
resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2"
integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg==
sonic-boom@^1.0.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e"
integrity sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==
dependencies:
atomic-sleep "^1.0.0"
flatstr "^1.0.12"
string-similarity@^4.0.1:
version "4.0.4"
resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b"
integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==
tiny-lru@^7.0.0:
version "7.0.6"
resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-7.0.6.tgz#b0c3cdede1e5882aa2d1ae21cb2ceccf2a331f24"
integrity sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==

View File

@@ -2,6 +2,7 @@ package ch.unisg.tapas;
import ch.unisg.tapas.auctionhouse.adapter.common.clients.TapasMqttClient;
import ch.unisg.tapas.auctionhouse.adapter.in.messaging.mqtt.AuctionEventsMqttDispatcher;
import ch.unisg.tapas.auctionhouse.domain.AuctionHouseDiscovery;
import ch.unisg.tapas.auctionhouse.adapter.common.clients.WebSubSubscriber;
import ch.unisg.tapas.common.AuctionHouseResourceDirectory;
import ch.unisg.tapas.common.ConfigProperties;
@@ -16,6 +17,9 @@ import org.springframework.core.env.ConfigurableEnvironment;
import java.net.URI;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Main TAPAS Auction House application.
@@ -24,7 +28,7 @@ import java.util.List;
public class TapasAuctionHouseApplication {
private static final Logger LOGGER = LogManager.getLogger(TapasAuctionHouseApplication.class);
public static String RESOURCE_DIRECTORY = "https://api.interactions.ics.unisg.ch/auction-houses/";
public static String RESOURCE_DIRECTORY = "http://localhost:3500";
public static String DEFAULT_MQTT_BROKER = "tcp://broker.hivemq.com:1883";
private static ConfigurableEnvironment ENVIRONMENT;
@@ -36,20 +40,23 @@ public class TapasAuctionHouseApplication {
// TODO Set start up of message services with config
// We will use these bootstrap methods in Week 6:
// bootstrapMarketplaceWithWebSub();
bootstrapMarketplaceWithWebSub();
bootstrapMarketplaceWithMqtt();
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(crawlerRunnable, 30, 30, TimeUnit.SECONDS);
}
/**
* Discovers auction houses and subscribes to WebSub notifications
*/
private static void bootstrapMarketplaceWithWebSub() {
List<String> auctionHouseEndpoints = discoverAuctionHouseEndpoints();
discoverAuctionHouseEndpoints();
WebSubSubscriber subscriber = new WebSubSubscriber();
// WebSubSubscriber subscriber = new WebSubSubscriber();
for (String endpoint : auctionHouseEndpoints) {
subscriber.subscribeToAuctionHouseEndpoint(URI.create(endpoint));
}
// for (String endpoint : auctionHouseEndpoints) {
// subscriber.subscribeToAuctionHouseEndpoint(URI.create(endpoint));
// }
}
/**
@@ -74,11 +81,22 @@ public class TapasAuctionHouseApplication {
}
}
private static List<String> discoverAuctionHouseEndpoints() {
private static void discoverAuctionHouseEndpoints() {
AuctionHouseResourceDirectory rd = new AuctionHouseResourceDirectory(
URI.create(RESOURCE_DIRECTORY)
);
return rd.retrieveAuctionHouseEndpoints();
AuctionHouseDiscovery.getInstance().addAuctionHouseDiscoveryInformation(rd.retrieveAuctionHouseEndpoints());
}
private static Runnable crawlerRunnable = new Runnable() {
public void run() {
AuctionHouseResourceDirectory rd = new AuctionHouseResourceDirectory(
URI.create(RESOURCE_DIRECTORY)
);
AuctionHouseDiscovery.getInstance().addAuctionHouseDiscoveryInformation(rd.retrieveAuctionHouseEndpoints());
}
};
}

View File

@@ -0,0 +1,48 @@
package ch.unisg.tapas.auctionhouse.adapter.common.formats;
import ch.unisg.tapas.auctionhouse.domain.AuctionHouseDiscoveryInformation;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;
public class AuctionHouseDiscoveryJsonRepresentation {
public static final String MEDIA_TYPE = "application/auctionhousediscovery+json";
@Getter @Setter
private String auctionHouseUri;
@Getter @Setter
private String webSubUri;
@Getter @Setter
private List<String> taskTypes;
@Getter @Setter
private String timeStamp;
@Getter @Setter
private String groupName;
public AuctionHouseDiscoveryJsonRepresentation() {}
public AuctionHouseDiscoveryJsonRepresentation(AuctionHouseDiscoveryInformation auctionHouseDiscoveryInformation){
this.auctionHouseUri = auctionHouseDiscoveryInformation.getAuctionHouseUri().getValue().toString();
this.webSubUri = auctionHouseDiscoveryInformation.getWebSubUri().getValue().toString();
this.taskTypes = auctionHouseDiscoveryInformation.getTaskTypes().getValue();
this.timeStamp = auctionHouseDiscoveryInformation.getTimeStamp().getValue().toString();
this.groupName = auctionHouseDiscoveryInformation.getGroupName().getValue();
}
public static String serialize(AuctionHouseDiscoveryInformation auctionHouseDiscoveryInformation) throws JsonProcessingException {
AuctionHouseDiscoveryJsonRepresentation representation = new AuctionHouseDiscoveryJsonRepresentation(auctionHouseDiscoveryInformation);
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return mapper.writeValueAsString(representation);
}
}

View File

@@ -0,0 +1,51 @@
package ch.unisg.tapas.auctionhouse.adapter.in.web;
import ch.unisg.tapas.auctionhouse.adapter.common.formats.AuctionHouseDiscoveryJsonRepresentation;
import ch.unisg.tapas.auctionhouse.application.port.in.AuctionHouseDiscoveryUseCase;
import ch.unisg.tapas.auctionhouse.domain.AuctionHouseDiscoveryInformation;
import java.util.List;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Controller that handles HTTP requests for the auction house discovery. This controller implements
* the {@link AuctionHouseDiscoveryUseCase} use case using the {@link AuctionHouseDiscoveryCommand} command.
*/
@RestController
public class AuctionHouseDiscoveryWebController {
private final AuctionHouseDiscoveryUseCase auctionHouseDiscoveryUseCase;
public AuctionHouseDiscoveryWebController(AuctionHouseDiscoveryUseCase auctionHouseDiscoveryUseCase) {
this.auctionHouseDiscoveryUseCase = auctionHouseDiscoveryUseCase;
}
@GetMapping(path="/discovery/", consumes = AuctionHouseDiscoveryJsonRepresentation.MEDIA_TYPE)
public ResponseEntity<String> auctionHouseDiscovery() {
List<AuctionHouseDiscoveryInformation> auctionHouseDiscoveryInformation = auctionHouseDiscoveryUseCase.auctionHouseDiscovery();
ObjectMapper mapper = new ObjectMapper();
ObjectNode response = mapper.createObjectNode();
ArrayNode array = response.putArray("auctionHouseInfo");
for (AuctionHouseDiscoveryInformation info : auctionHouseDiscoveryInformation) {
array.add(mapper.valueToTree(new AuctionHouseDiscoveryJsonRepresentation(info)));
}
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add(HttpHeaders.CONTENT_TYPE, AuctionHouseDiscoveryJsonRepresentation.MEDIA_TYPE);
return new ResponseEntity<>(response.toString(), responseHeaders, HttpStatus.OK);
}
}

View File

@@ -0,0 +1,76 @@
package ch.unisg.tapas.auctionhouse.adapter.out.web;
import ch.unisg.tapas.auctionhouse.application.port.out.AuctionHouseDiscoveryPort;
import ch.unisg.tapas.auctionhouse.domain.AuctionHouseDiscoveryInformation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONObject;
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.sql.Timestamp;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class AuctionHouseDiscoveryHttpAdapter implements AuctionHouseDiscoveryPort {
private static final Logger LOGGER = LogManager.getLogger(AuctionHouseDiscoveryHttpAdapter.class);
public List<AuctionHouseDiscoveryInformation> fetchAuctionHouseInformation(URI auctionHouseURI){
System.out.println(auctionHouseURI);
try{
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(auctionHouseURI)
.GET()
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
LOGGER.info(response.body());
var responseBody = new JSONObject(response.body());
var arrayOfInformation = responseBody.getJSONArray("auctionHouseInfo");
var returnList = new LinkedList<AuctionHouseDiscoveryInformation>();
for(int i = 0; i < arrayOfInformation.length(); i++)
{
var informationJSON = arrayOfInformation.getJSONObject(i);
var information = new AuctionHouseDiscoveryInformation(
new AuctionHouseDiscoveryInformation.AuctionHouseUri(URI.create(informationJSON.getString("auctionHouseURI"))),
new AuctionHouseDiscoveryInformation.WebSubUri(URI.create(informationJSON.getString("webSubURI"))),
new AuctionHouseDiscoveryInformation.TaskTypes(getTaskTypes(informationJSON.getJSONArray("taskTypes"))),
new AuctionHouseDiscoveryInformation.TimeStamp(Timestamp.valueOf(informationJSON.getString("timeStamp"))),
new AuctionHouseDiscoveryInformation.GroupName(informationJSON.getString("groupName"))
);
returnList.add(information);
}
return returnList;
} catch (IOException e) {
e.printStackTrace();
return Collections.<AuctionHouseDiscoveryInformation>emptyList();
} catch (InterruptedException e) {
e.printStackTrace();
return Collections.<AuctionHouseDiscoveryInformation>emptyList();
}
}
private List<String> getTaskTypes(JSONArray arrayOfTypes){
var listOfTypes = new LinkedList<String>();
for(int i = 0; i < arrayOfTypes.length(); i++)
{
listOfTypes.add(arrayOfTypes.getString(i));
}
return listOfTypes;
}
}

View File

@@ -0,0 +1,9 @@
package ch.unisg.tapas.auctionhouse.application.port.in;
import java.util.List;
import ch.unisg.tapas.auctionhouse.domain.AuctionHouseDiscoveryInformation;
public interface AuctionHouseDiscoveryUseCase {
List<AuctionHouseDiscoveryInformation> auctionHouseDiscovery();
}

View File

@@ -0,0 +1,10 @@
package ch.unisg.tapas.auctionhouse.application.port.out;
import ch.unisg.tapas.auctionhouse.domain.AuctionHouseDiscoveryInformation;
import java.net.URI;
import java.util.List;
public interface AuctionHouseDiscoveryPort {
List<AuctionHouseDiscoveryInformation> fetchAuctionHouseInformation(URI auctionHouseURI);
}

View File

@@ -0,0 +1,19 @@
package ch.unisg.tapas.auctionhouse.application.service;
import java.util.List;
import org.springframework.stereotype.Component;
import ch.unisg.tapas.auctionhouse.application.port.in.AuctionHouseDiscoveryUseCase;
import ch.unisg.tapas.auctionhouse.domain.AuctionHouseDiscovery;
import ch.unisg.tapas.auctionhouse.domain.AuctionHouseDiscoveryInformation;
@Component
public class AuctionHouseDiscoveryService implements AuctionHouseDiscoveryUseCase {
@Override
public List<AuctionHouseDiscoveryInformation> auctionHouseDiscovery() {
return AuctionHouseDiscovery.getInstance().getAuctionHouseDiscoveryList();
}
}

View File

@@ -0,0 +1,73 @@
package ch.unisg.tapas.auctionhouse.domain;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import lombok.Getter;
public class AuctionHouseDiscovery {
private static final AuctionHouseDiscovery auctionHouseDiscovery = new AuctionHouseDiscovery();
private final List<String> tasktypes = new ArrayList<String>() {
{
add("computation");
add("smallrobot");
}
};
@Getter
private List<AuctionHouseDiscoveryInformation> auctionHouseDiscoveryList = new ArrayList<>() {
};
private AuctionHouseDiscovery() {
try {
// Add our information to list
auctionHouseDiscoveryList.add(new AuctionHouseDiscoveryInformation(
new AuctionHouseDiscoveryInformation.AuctionHouseUri(new URI("http://localhost:8086")),
new AuctionHouseDiscoveryInformation.WebSubUri(new URI("http://localhost:8086/websub")),
new AuctionHouseDiscoveryInformation.TaskTypes(tasktypes),
new AuctionHouseDiscoveryInformation.TimeStamp(new Timestamp(new Date().getTime())),
new AuctionHouseDiscoveryInformation.GroupName("Group 1")
));
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static AuctionHouseDiscovery getInstance() {
return auctionHouseDiscovery;
}
public List<AuctionHouseDiscoveryInformation> getAuctionHouseDiscoveryInformation() {
return auctionHouseDiscoveryList;
}
public void addAuctionHouseDiscoveryInformation(List<AuctionHouseDiscoveryInformation> informations) {
outerloop:
for (AuctionHouseDiscoveryInformation discovery : informations) {
for (AuctionHouseDiscoveryInformation endpoint : auctionHouseDiscoveryList) {
// Check if discovery is already in our discovery list
if (endpoint.getAuctionHouseUri().getValue().toString().equals(discovery.getAuctionHouseUri().getValue().toString())) {
// Check if the new discovery is more recent than the current
if (endpoint.getTimeStamp().getValue().before(discovery.getTimeStamp().getValue())) {
// Endpoint information is older. Remove and add the new discovery to the list
auctionHouseDiscoveryList.remove(endpoint);
break;
} else {
continue outerloop;
}
}
}
auctionHouseDiscoveryList.add(discovery);
}
}
}

View File

@@ -0,0 +1,65 @@
package ch.unisg.tapas.auctionhouse.domain;
import lombok.Getter;
import lombok.Value;
import java.net.URI;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
//TODO: change to array type
public class AuctionHouseDiscoveryInformation {
@Getter
private final AuctionHouseUri auctionHouseUri;
@Getter
private final WebSubUri webSubUri;
@Getter
private final TaskTypes taskTypes;
@Getter
private final TimeStamp timeStamp;
//Had to initialize this in the constructor, but it's not required, so I'm not sure
//if this is correct
@Getter
private final GroupName groupName;
public AuctionHouseDiscoveryInformation(AuctionHouseUri auctionHouseUri, WebSubUri webSubUri,
TaskTypes taskTypes, TimeStamp timeStamp, GroupName groupName){
this.auctionHouseUri = auctionHouseUri;
this.webSubUri = webSubUri;
this.taskTypes = taskTypes;
this.timeStamp = timeStamp;
this.groupName = groupName; //see above
}
@Value
public static class AuctionHouseUri {
private URI value;
}
@Value
public static class WebSubUri {
private URI value;
}
@Value
public static class TaskTypes {
private List<String> value;
}
@Value
public static class TimeStamp {
private Timestamp value;
}
@Value
public static class GroupName {
private String value;
}
}

View File

@@ -3,8 +3,13 @@ package ch.unisg.tapas.common;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import ch.unisg.tapas.auctionhouse.adapter.out.web.AuctionHouseDiscoveryHttpAdapter;
import ch.unisg.tapas.auctionhouse.application.port.out.AuctionHouseDiscoveryPort;
import ch.unisg.tapas.auctionhouse.domain.AuctionHouseDiscoveryInformation;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
@@ -26,32 +31,68 @@ public class AuctionHouseResourceDirectory {
this.rdEndpoint = rdEndpoint;
}
private AuctionHouseDiscoveryPort auctionHouseDiscoveryport = new AuctionHouseDiscoveryHttpAdapter();
private List<AuctionHouseDiscoveryInformation> auctionHouseEndpoints = new ArrayList<>();
// List to keep track of already fetched endpoints
private List<URI> fetchedEndpoints = new ArrayList<>();
/**
* Retrieves the endpoints of all auctions houses registered with this directory.
* @return
*/
public List<String> retrieveAuctionHouseEndpoints() {
List<String> auctionHouseEndpoints = new ArrayList<>();
public List<AuctionHouseDiscoveryInformation> retrieveAuctionHouseEndpoints() {
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(rdEndpoint).GET().build();
fetchedEndpoints.clear();
auctionHouseEndpoints.clear();
HttpResponse<String> response = HttpClient.newBuilder().build()
.send(request, HttpResponse.BodyHandlers.ofString());
// For simplicity, here we just hard code the current representation used by our
// resource directory for auction houses
ObjectMapper objectMapper = new ObjectMapper();
JsonNode payload = objectMapper.readTree(response.body());
for (JsonNode node : payload) {
auctionHouseEndpoints.add(node.get("endpoint").asText());
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
fetchedEndpoints.add(rdEndpoint);
// Start recusive fetching of auctionhouses
fetchEndpoints(getInformation(rdEndpoint));
return auctionHouseEndpoints;
}
// Recursive function to fetch all endpoints
private void fetchEndpoints(List<AuctionHouseDiscoveryInformation> auctionHouses) {
for (AuctionHouseDiscoveryInformation ah : auctionHouses) {
if (!fetchedEndpoints.contains(ah.getAuctionHouseUri().getValue())) {
fetchedEndpoints.add(ah.getAuctionHouseUri().getValue());
fetchEndpoints(getInformation(ah.getAuctionHouseUri().getValue()));
}
}
}
private List<AuctionHouseDiscoveryInformation> getInformation(URI uri) {
List<AuctionHouseDiscoveryInformation> discoveries;
try {
discoveries = auctionHouseDiscoveryport.fetchAuctionHouseInformation(new URI(uri.toString() + "/discovery/"));
outerloop:
for (AuctionHouseDiscoveryInformation discovery : discoveries) {
for (AuctionHouseDiscoveryInformation endpoint : auctionHouseEndpoints) {
// Check if discovery is already in our endpoint list
if (endpoint.getAuctionHouseUri().getValue().toString().equals(discovery.getAuctionHouseUri().getValue().toString())) {
// Check if the new discovery is more recent than the current
if (endpoint.getTimeStamp().getValue().before(discovery.getTimeStamp().getValue())) {
// Endpoint information is older. Remove and add the new discovery to the list
auctionHouseEndpoints.remove(endpoint);
break;
} else {
continue outerloop;
}
}
}
auctionHouseEndpoints.add(discovery);
}
return discoveries;
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// When an error happens return empty list
return new ArrayList<AuctionHouseDiscoveryInformation>();
}
}