From 28964305d6e66bdae6310ebc7e746773bec02c77 Mon Sep 17 00:00:00 2001
From: thijsheijden <hi@thijsheijden.nl>
Date: Fri, 15 Oct 2021 12:59:24 +0200
Subject: [PATCH] Added query-orchestrator code and fixed imports

---
 .gitignore                                    |   2 +
 Dockerfile                                    |  39 +++
 LICENSE                                       |  21 ++
 Makefile                                      |  52 +++
 cmd/schema-orchestrator/main.go               |  51 +++
 deployments/deployment.yml                    |  98 ++++++
 go.mod                                        |  10 +
 go.sum                                        | 220 +++++++++++++
 .../databaseTypeService/databaseType.pb.go    | 297 ++++++++++++++++++
 .../databaseType_grpc.pb.go                   | 106 +++++++
 internal/drivers/rpcdriver/getDatabaseType.go |  47 +++
 internal/drivers/rpcdriver/grpcdriver.go      |  19 ++
 internal/drivers/rpcdriver/interface.go       |  13 +
 internal/drivers/webdriver/cors.go            |  20 ++
 internal/drivers/webdriver/executequery.go    |  77 +++++
 internal/drivers/webdriver/interface.go       |  20 ++
 .../drivers/webdriver/retrieveCachedQuery.go  |  64 ++++
 internal/drivers/webdriver/web.go             |  48 +++
 internal/entity/jwt.go                        |  17 +
 internal/entity/queryID.go                    |  13 +
 internal/entity/retrieveCachedQueryRequest.go |  37 +++
 internal/usecases/auth/interface.go           |  13 +
 internal/usecases/auth/jwt.go                 |  40 +++
 internal/usecases/auth/validate.go            |  28 ++
 internal/usecases/produce/interface.go        |  14 +
 internal/usecases/produce/produce.go          |  53 ++++
 .../usecases/produce/produceCachedQuery.go    |  34 ++
 .../produce/produceQueryExecutionMessage.go   |  43 +++
 internal/usecases/retrievequery/interface.go  |  13 +
 .../retrievequery/retrieveCachedQuery.go      |  34 ++
 .../usecases/retrievequery/retrievequery.go   |  26 ++
 internal/usecases/web/StartListener.go        |  14 +
 internal/usecases/web/interface.go            |  20 ++
 internal/usecases/web/setuphandlers.go        |  22 ++
 internal/usecases/web/web.go                  |  26 ++
 35 files changed, 1651 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Dockerfile
 create mode 100644 LICENSE
 create mode 100644 Makefile
 create mode 100644 cmd/schema-orchestrator/main.go
 create mode 100644 deployments/deployment.yml
 create mode 100644 go.sum
 create mode 100644 internal/drivers/rpcdriver/databaseTypeService/databaseType.pb.go
 create mode 100644 internal/drivers/rpcdriver/databaseTypeService/databaseType_grpc.pb.go
 create mode 100644 internal/drivers/rpcdriver/getDatabaseType.go
 create mode 100644 internal/drivers/rpcdriver/grpcdriver.go
 create mode 100644 internal/drivers/rpcdriver/interface.go
 create mode 100644 internal/drivers/webdriver/cors.go
 create mode 100644 internal/drivers/webdriver/executequery.go
 create mode 100644 internal/drivers/webdriver/interface.go
 create mode 100644 internal/drivers/webdriver/retrieveCachedQuery.go
 create mode 100644 internal/drivers/webdriver/web.go
 create mode 100644 internal/entity/jwt.go
 create mode 100644 internal/entity/queryID.go
 create mode 100644 internal/entity/retrieveCachedQueryRequest.go
 create mode 100644 internal/usecases/auth/interface.go
 create mode 100644 internal/usecases/auth/jwt.go
 create mode 100644 internal/usecases/auth/validate.go
 create mode 100644 internal/usecases/produce/interface.go
 create mode 100644 internal/usecases/produce/produce.go
 create mode 100644 internal/usecases/produce/produceCachedQuery.go
 create mode 100644 internal/usecases/produce/produceQueryExecutionMessage.go
 create mode 100644 internal/usecases/retrievequery/interface.go
 create mode 100644 internal/usecases/retrievequery/retrieveCachedQuery.go
 create mode 100644 internal/usecases/retrievequery/retrievequery.go
 create mode 100644 internal/usecases/web/StartListener.go
 create mode 100644 internal/usecases/web/interface.go
 create mode 100644 internal/usecases/web/setuphandlers.go
 create mode 100644 internal/usecases/web/web.go

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6c8563b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+builds/
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..de2959f
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,39 @@
+# docker buildx build --platform linux/amd64,linux/arm64 -t datastropheregistry.azurecr.io/query-orchestrator . --push --ssh default
+# STAGE 1
+FROM golang:1.16
+
+ARG TARGETARCH
+ARG TARGETOS
+
+WORKDIR /app
+
+# Use SSH instead of HTTPS
+RUN echo "[url \"git@git.science.uu.nl:\"]\n\tinsteadOf = https://git.science.uu.nl/" >> /root/.gitconfig
+
+# Turn off strict host key checking
+RUN mkdir /root/.ssh && echo "StrictHostKeyChecking no " > /root/.ssh/config
+
+# Copy go files into the image
+COPY go.mod ./
+COPY go.sum ./
+COPY cmd/ ./cmd/
+COPY internal/ ./internal/
+COPY pkg/ ./pkg/
+
+# Gather dependencies
+RUN --mount=type=ssh go mod download
+
+# Compile for the target architecture and operating system
+# Add SSH mount as this operation requires access to private repos
+RUN GOARCH=${TARGETARCH} GOOS=${TARGETOS} CGO_ENABLED=0 go build -o ./main ./cmd/query-orchestrator/
+
+# STAGE 2
+FROM busybox
+
+WORKDIR /app
+
+# Copy the built binary into this image
+COPY --from=0 /app/main ./
+
+# Run the binary
+CMD ./main
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ed9914c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) Utrecht University (Department of Information and Computing Sciences)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..981efec
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,52 @@
+.PHONY: all dep build test lint
+
+lint: dep ## Lint the files
+	@golint -set_exit_status ./...
+
+test: dep ## Run unittests
+	@go test -cover -coverprofile=coverage.txt -covermode count ./...
+
+dep: login ## Get the dependencies
+	@go get -a -v ./...
+	@go get -u golang.org/x/lint/golint
+	@go get -u github.com/boumenot/gocover-cobertura
+
+coverage: dep
+	@go test -v -coverpkg=./... -coverprofile=cover.out ./...
+	@go tool cover -func cover.out | grep total
+	@go tool cover -html=cover.out -o cover.html
+
+windows:
+	$(eval export GOOS := windows)
+	@go build -o builds/main ./cmd/schema-orchestrator/
+
+macos:
+	$(eval export GOOS := darwin)
+	@go build -o builds/main ./cmd/schema-orchestrator/
+
+linux: login # Build for linux
+	$(eval export GOOS := linux)
+	CGO_ENABLED=0 go build -o builds/main ./cmd/schema-orchestrator/
+
+run:
+	./builds/main
+
+develop:
+	$(eval export RABBIT_USER := guest)
+	$(eval export RABBIT_PASSWORD := guest)
+	$(eval export RABBIT_HOST := localhost)
+	$(eval export RABBIT_PORT := 5672)
+
+	$(eval export JWT_SECRET := 15D262E1FB339FFBD062FFB81C1831B2757FA3F1C02B7432A3E586A447FB7870)
+
+	$(eval export LOG_MESSAGES := true)
+
+	@go run cmd/schema-orchestrator/main.go
+
+docker: login
+	make linux
+	@docker build -t datastropheregistry.azurecr.io/schema-orchestrator:latest .
+	@docker push datastropheregistry.azurecr.io/schema-orchestrator\:latest
+
+login:
+	echo -e "machine git.science.uu.nl\nlogin gitlab-ci-token\npassword ${CI_JOB_TOKEN}" > ~/.netrc
\ No newline at end of file
diff --git a/cmd/schema-orchestrator/main.go b/cmd/schema-orchestrator/main.go
new file mode 100644
index 0000000..f6cd485
--- /dev/null
+++ b/cmd/schema-orchestrator/main.go
@@ -0,0 +1,51 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package main
+
+import (
+	"schema-orchestrator/internal/drivers/rpcdriver"
+	"schema-orchestrator/internal/drivers/webdriver"
+	"schema-orchestrator/internal/usecases/auth"
+	"schema-orchestrator/internal/usecases/produce"
+	"schema-orchestrator/internal/usecases/retrievequery"
+	"schema-orchestrator/internal/usecases/web"
+
+	"git.science.uu.nl/graphpolaris/broker"
+	"git.science.uu.nl/graphpolaris/keyvaluestore"
+	"git.science.uu.nl/graphpolaris/objectstore"
+)
+
+/*
+This is the main method, it executes the code for this service
+*/
+func main() {
+	// Create rpcDriver
+	rpcDriver := rpcdriver.New()
+
+	// Create broker driver
+	brokerDriver := broker.NewDriver()
+
+	// Create object store driver
+	objectStore := objectstore.NewDriver()
+	objectStore.Connect()
+
+	webDriver := webdriver.CreateListener()
+
+	authService := auth.NewService()
+	webService := web.NewService(webDriver)
+
+	keyValueStore := keyvaluestore.NewDriver()
+	keyValueStore.Connect()
+
+	produceService := produce.NewService(brokerDriver, keyValueStore, rpcDriver)
+	produceService.Start()
+
+	retrieveService := retrievequery.NewService(objectStore)
+	webService.SetupHandlers(authService, produceService, retrieveService)
+	webService.StartListener()
+
+	select {}
+}
diff --git a/deployments/deployment.yml b/deployments/deployment.yml
new file mode 100644
index 0000000..28c464b
--- /dev/null
+++ b/deployments/deployment.yml
@@ -0,0 +1,98 @@
+#This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+#© Copyright Utrecht University (Department of Information and Computing Sciences)
+
+# Service that exposes this deployment
+kind: Service
+apiVersion: v1
+metadata:
+  name: schema-orchestrator
+spec:
+  selector:
+    app: schema-orchestrator
+  ports:
+    - port: 3000
+      targetPort: 3000
+
+---
+
+# schema orchestrator deployment
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: schema-orchestrator
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: schema-orchestrator
+  template:
+    metadata:
+      labels:
+        app: schema-orchestrator
+    spec:
+      containers:
+      - name: schema-orchestrator
+        image: datastropheregistry.azurecr.io/schema-orchestrator:latest
+        ports:
+        - containerPort: 3000 
+        env:
+        - name: RABBIT_HOST
+          value: rabbitmq
+        - name: RABBIT_PORT
+          value: "5672"
+        - name: RABBIT_USER
+          valueFrom:
+            secretKeyRef: 
+              name: rabbitmq-default-user
+              key: username
+        - name: RABBIT_PASSWORD
+          valueFrom:
+            secretKeyRef: 
+              name: rabbitmq-default-user
+              key: password
+        - name: REDIS_ADDRESS
+          value: redis.redis.svc.cluster.local:6379
+        - name: LOG_MESSAGES
+          value: "true"
+        - name: MINIO_ADDRESS
+          value: minio:9000
+        - name: MINIO_ACCESSKEYID
+          value: root
+        - name: MINIO_ACCESSKEY
+          value: DikkeDraak
+        - name: JWT_SECRET
+          valueFrom:
+            secretKeyRef: 
+              name: jwt-secret
+              key: secret
+        resources:
+          requests:
+            memory: "100Mi"
+            cpu: "100m"
+          limits:
+            memory: "250Mi"
+            cpu: "500m"
+      imagePullSecrets:
+      - name: docker-regcred
+
+---
+
+# Deployment autoscaler
+apiVersion: autoscaling/v2beta2
+kind: HorizontalPodAutoscaler
+metadata:
+  name: schema-orchestrator
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: schema-orchestrator
+  minReplicas: 1
+  maxReplicas: 3
+  metrics:
+  - type: Resource
+    resource:
+      name: cpu
+      target:
+        type: Utilization
+        averageUtilization: 80
diff --git a/go.mod b/go.mod
index 2e9c985..999ad37 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,13 @@
 module schema-orchestrator
 
 go 1.16
+
+require (
+	git.science.uu.nl/graphpolaris/broker v0.0.0-20210913145737-76d174f4367a
+	git.science.uu.nl/graphpolaris/keyvaluestore v0.0.0-20210913145832-4c76e9e5f5bd
+	git.science.uu.nl/graphpolaris/objectstore v0.0.0-20210913150113-977062fb8a3c
+	github.com/gbrlsnchs/jwt/v3 v3.0.1
+	github.com/rs/xid v1.2.1 // indirect
+	google.golang.org/grpc v1.41.0
+	google.golang.org/protobuf v1.25.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..f1fe8df
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,220 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+git.science.uu.nl/graphpolaris/broker v0.0.0-20210913145737-76d174f4367a h1:9DJdKbOJr9SsLKJWLdwC4FimlXs6zSbG1Z7LlHHD94g=
+git.science.uu.nl/graphpolaris/broker v0.0.0-20210913145737-76d174f4367a/go.mod h1:3aUI887geYzHv0P89dQ0xA/1LLHgNkvymsxjk2VZ8Q8=
+git.science.uu.nl/graphpolaris/keyvaluestore v0.0.0-20210913145832-4c76e9e5f5bd h1:rfoCSM9hWOj6S/tbD4ZHD5vcUMob/GF1Cr/XE/G4iGY=
+git.science.uu.nl/graphpolaris/keyvaluestore v0.0.0-20210913145832-4c76e9e5f5bd/go.mod h1:r62eFpVrFJldxyr0AC2ww7pDcEVUpdAh4X9YdsGEzss=
+git.science.uu.nl/graphpolaris/objectstore v0.0.0-20210913150113-977062fb8a3c h1:yJKWwDCVbdh0GrQf8Ggenf/aFbJxc6u4m3Cb34s7uKw=
+git.science.uu.nl/graphpolaris/objectstore v0.0.0-20210913150113-977062fb8a3c/go.mod h1:JTrEtLWqP0uUvOdS8l5+nINwHSoY1KwRYL1i86D/WCU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/gbrlsnchs/jwt/v3 v3.0.1 h1:lbUmgAKpxnClrKloyIwpxm4OuWeDl5wLk52G91ODPw4=
+github.com/gbrlsnchs/jwt/v3 v3.0.1/go.mod h1:AncDcjXz18xetI3A6STfXq2w+LuTx8pQ8bGEwRN8zVM=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-redis/redis/v8 v8.8.2 h1:O/NcHqobw7SEptA0yA6up6spZVFtwE06SXM8rgLtsP8=
+github.com/go-redis/redis/v8 v8.8.2/go.mod h1:F7resOH5Kdug49Otu24RjHWwgK7u9AmtqWMnCV1iP5Y=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
+github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magefile/mage v1.9.0 h1:t3AU2wNwehMCW97vuqQLtw6puppWXHO+O2MHo5a50XE=
+github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
+github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
+github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
+github.com/minio/minio-go/v7 v7.0.10 h1:1oUKe4EOPUEhw2qnPQaPsJ0lmVTYLFu03SiItauXs94=
+github.com/minio/minio-go/v7 v7.0.10/go.mod h1:td4gW1ldOsj1PbSNS+WYK43j+P1XVhX/8W8awaYlBFo=
+github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
+github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo=
+github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/thijsheijden/alice v0.1.18 h1:lHmhzruprpH0FH6XlCg8zDqTZI15Iuuj9VCNvH6a8Wc=
+github.com/thijsheijden/alice v0.1.18/go.mod h1:lYOP30HKhw/7xJa3lLhs+Xsdc5T7MRo7DOb/npzfg9I=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.opentelemetry.io/otel v0.19.0 h1:Lenfy7QHRXPZVsw/12CWpxX6d/JkrX8wrx2vO8G80Ng=
+go.opentelemetry.io/otel v0.19.0/go.mod h1:j9bF567N9EfomkSidSfmMwIwIBuP37AMAIzVW85OxSg=
+go.opentelemetry.io/otel/metric v0.19.0 h1:dtZ1Ju44gkJkYvo+3qGqVXmf88tc+a42edOywypengg=
+go.opentelemetry.io/otel/metric v0.19.0/go.mod h1:8f9fglJPRnXuskQmKpnad31lcLJ2VmNNqIsx/uIwBSc=
+go.opentelemetry.io/otel/oteltest v0.19.0/go.mod h1:tI4yxwh8U21v7JD6R3BcA/2+RBoTKFexE/PJ/nSO7IA=
+go.opentelemetry.io/otel/trace v0.19.0 h1:1ucYlenXIDA1OlHVLDZKX0ObXV5RLaq06DtUKz5e5zc=
+go.opentelemetry.io/otel/trace v0.19.0/go.mod h1:4IXiNextNOpPnRlI4ryK69mn5iC84bjBWZQA5DXz/qg=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
+golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
+google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
+gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/internal/drivers/rpcdriver/databaseTypeService/databaseType.pb.go b/internal/drivers/rpcdriver/databaseTypeService/databaseType.pb.go
new file mode 100644
index 0000000..00b3853
--- /dev/null
+++ b/internal/drivers/rpcdriver/databaseTypeService/databaseType.pb.go
@@ -0,0 +1,297 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.14.0
+// source: databaseType.proto
+
+package databaseTypeService
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type DatabaseTypeResponse_DatabaseType int32
+
+const (
+	DatabaseTypeResponse_ARANGODB DatabaseTypeResponse_DatabaseType = 0
+	DatabaseTypeResponse_NEO4J    DatabaseTypeResponse_DatabaseType = 1
+)
+
+// Enum value maps for DatabaseTypeResponse_DatabaseType.
+var (
+	DatabaseTypeResponse_DatabaseType_name = map[int32]string{
+		0: "ARANGODB",
+		1: "NEO4J",
+	}
+	DatabaseTypeResponse_DatabaseType_value = map[string]int32{
+		"ARANGODB": 0,
+		"NEO4J":    1,
+	}
+)
+
+func (x DatabaseTypeResponse_DatabaseType) Enum() *DatabaseTypeResponse_DatabaseType {
+	p := new(DatabaseTypeResponse_DatabaseType)
+	*p = x
+	return p
+}
+
+func (x DatabaseTypeResponse_DatabaseType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (DatabaseTypeResponse_DatabaseType) Descriptor() protoreflect.EnumDescriptor {
+	return file_databaseType_proto_enumTypes[0].Descriptor()
+}
+
+func (DatabaseTypeResponse_DatabaseType) Type() protoreflect.EnumType {
+	return &file_databaseType_proto_enumTypes[0]
+}
+
+func (x DatabaseTypeResponse_DatabaseType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use DatabaseTypeResponse_DatabaseType.Descriptor instead.
+func (DatabaseTypeResponse_DatabaseType) EnumDescriptor() ([]byte, []int) {
+	return file_databaseType_proto_rawDescGZIP(), []int{1, 0}
+}
+
+type DatabaseTypeRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ClientID     string `protobuf:"bytes,1,opt,name=clientID,proto3" json:"clientID,omitempty"`
+	DatabaseName string `protobuf:"bytes,2,opt,name=databaseName,proto3" json:"databaseName,omitempty"`
+}
+
+func (x *DatabaseTypeRequest) Reset() {
+	*x = DatabaseTypeRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_databaseType_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DatabaseTypeRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DatabaseTypeRequest) ProtoMessage() {}
+
+func (x *DatabaseTypeRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_databaseType_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DatabaseTypeRequest.ProtoReflect.Descriptor instead.
+func (*DatabaseTypeRequest) Descriptor() ([]byte, []int) {
+	return file_databaseType_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *DatabaseTypeRequest) GetClientID() string {
+	if x != nil {
+		return x.ClientID
+	}
+	return ""
+}
+
+func (x *DatabaseTypeRequest) GetDatabaseName() string {
+	if x != nil {
+		return x.DatabaseName
+	}
+	return ""
+}
+
+type DatabaseTypeResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Error        string                            `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
+	DatabaseType DatabaseTypeResponse_DatabaseType `protobuf:"varint,2,opt,name=databaseType,proto3,enum=DatabaseTypeResponse_DatabaseType" json:"databaseType,omitempty"`
+}
+
+func (x *DatabaseTypeResponse) Reset() {
+	*x = DatabaseTypeResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_databaseType_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DatabaseTypeResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DatabaseTypeResponse) ProtoMessage() {}
+
+func (x *DatabaseTypeResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_databaseType_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DatabaseTypeResponse.ProtoReflect.Descriptor instead.
+func (*DatabaseTypeResponse) Descriptor() ([]byte, []int) {
+	return file_databaseType_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *DatabaseTypeResponse) GetError() string {
+	if x != nil {
+		return x.Error
+	}
+	return ""
+}
+
+func (x *DatabaseTypeResponse) GetDatabaseType() DatabaseTypeResponse_DatabaseType {
+	if x != nil {
+		return x.DatabaseType
+	}
+	return DatabaseTypeResponse_ARANGODB
+}
+
+var File_databaseType_proto protoreflect.FileDescriptor
+
+var file_databaseType_proto_rawDesc = []byte{
+	0x0a, 0x12, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x22, 0x55, 0x0a, 0x13, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+	0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x61, 0x74, 0x61, 0x62,
+	0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64,
+	0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x9d, 0x01, 0x0a, 0x14,
+	0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x46, 0x0a, 0x0c, 0x64, 0x61,
+	0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e,
+	0x32, 0x22, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+	0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x79,
+	0x70, 0x65, 0x22, 0x27, 0x0a, 0x0c, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x79,
+	0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x52, 0x41, 0x4e, 0x47, 0x4f, 0x44, 0x42, 0x10, 0x00,
+	0x12, 0x09, 0x0a, 0x05, 0x4e, 0x45, 0x4f, 0x34, 0x4a, 0x10, 0x01, 0x32, 0x57, 0x0a, 0x13, 0x44,
+	0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69,
+	0x63, 0x65, 0x12, 0x40, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+	0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+	0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x44, 0x61,
+	0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x22, 0x00, 0x42, 0x47, 0x5a, 0x45, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x6d, 0x61, 0x6e,
+	0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f,
+	0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2f,
+	0x72, 0x70, 0x63, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+	0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_databaseType_proto_rawDescOnce sync.Once
+	file_databaseType_proto_rawDescData = file_databaseType_proto_rawDesc
+)
+
+func file_databaseType_proto_rawDescGZIP() []byte {
+	file_databaseType_proto_rawDescOnce.Do(func() {
+		file_databaseType_proto_rawDescData = protoimpl.X.CompressGZIP(file_databaseType_proto_rawDescData)
+	})
+	return file_databaseType_proto_rawDescData
+}
+
+var file_databaseType_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_databaseType_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_databaseType_proto_goTypes = []interface{}{
+	(DatabaseTypeResponse_DatabaseType)(0), // 0: DatabaseTypeResponse.DatabaseType
+	(*DatabaseTypeRequest)(nil),            // 1: DatabaseTypeRequest
+	(*DatabaseTypeResponse)(nil),           // 2: DatabaseTypeResponse
+}
+var file_databaseType_proto_depIdxs = []int32{
+	0, // 0: DatabaseTypeResponse.databaseType:type_name -> DatabaseTypeResponse.DatabaseType
+	1, // 1: DatabaseTypeService.GetDatabaseType:input_type -> DatabaseTypeRequest
+	2, // 2: DatabaseTypeService.GetDatabaseType:output_type -> DatabaseTypeResponse
+	2, // [2:3] is the sub-list for method output_type
+	1, // [1:2] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_databaseType_proto_init() }
+func file_databaseType_proto_init() {
+	if File_databaseType_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_databaseType_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DatabaseTypeRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_databaseType_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DatabaseTypeResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_databaseType_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_databaseType_proto_goTypes,
+		DependencyIndexes: file_databaseType_proto_depIdxs,
+		EnumInfos:         file_databaseType_proto_enumTypes,
+		MessageInfos:      file_databaseType_proto_msgTypes,
+	}.Build()
+	File_databaseType_proto = out.File
+	file_databaseType_proto_rawDesc = nil
+	file_databaseType_proto_goTypes = nil
+	file_databaseType_proto_depIdxs = nil
+}
diff --git a/internal/drivers/rpcdriver/databaseTypeService/databaseType_grpc.pb.go b/internal/drivers/rpcdriver/databaseTypeService/databaseType_grpc.pb.go
new file mode 100644
index 0000000..be95959
--- /dev/null
+++ b/internal/drivers/rpcdriver/databaseTypeService/databaseType_grpc.pb.go
@@ -0,0 +1,106 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package databaseTypeService
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// DatabaseTypeServiceClient is the client API for DatabaseTypeService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type DatabaseTypeServiceClient interface {
+	GetDatabaseType(ctx context.Context, in *DatabaseTypeRequest, opts ...grpc.CallOption) (*DatabaseTypeResponse, error)
+}
+
+type databaseTypeServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewDatabaseTypeServiceClient(cc grpc.ClientConnInterface) DatabaseTypeServiceClient {
+	return &databaseTypeServiceClient{cc}
+}
+
+func (c *databaseTypeServiceClient) GetDatabaseType(ctx context.Context, in *DatabaseTypeRequest, opts ...grpc.CallOption) (*DatabaseTypeResponse, error) {
+	out := new(DatabaseTypeResponse)
+	err := c.cc.Invoke(ctx, "/DatabaseTypeService/GetDatabaseType", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// DatabaseTypeServiceServer is the server API for DatabaseTypeService service.
+// All implementations must embed UnimplementedDatabaseTypeServiceServer
+// for forward compatibility
+type DatabaseTypeServiceServer interface {
+	GetDatabaseType(context.Context, *DatabaseTypeRequest) (*DatabaseTypeResponse, error)
+	mustEmbedUnimplementedDatabaseTypeServiceServer()
+}
+
+// UnimplementedDatabaseTypeServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedDatabaseTypeServiceServer struct {
+}
+
+func (UnimplementedDatabaseTypeServiceServer) GetDatabaseType(context.Context, *DatabaseTypeRequest) (*DatabaseTypeResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetDatabaseType not implemented")
+}
+func (UnimplementedDatabaseTypeServiceServer) mustEmbedUnimplementedDatabaseTypeServiceServer() {}
+
+// UnsafeDatabaseTypeServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to DatabaseTypeServiceServer will
+// result in compilation errors.
+type UnsafeDatabaseTypeServiceServer interface {
+	mustEmbedUnimplementedDatabaseTypeServiceServer()
+}
+
+func RegisterDatabaseTypeServiceServer(s grpc.ServiceRegistrar, srv DatabaseTypeServiceServer) {
+	s.RegisterService(&DatabaseTypeService_ServiceDesc, srv)
+}
+
+func _DatabaseTypeService_GetDatabaseType_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(DatabaseTypeRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(DatabaseTypeServiceServer).GetDatabaseType(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/DatabaseTypeService/GetDatabaseType",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(DatabaseTypeServiceServer).GetDatabaseType(ctx, req.(*DatabaseTypeRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// DatabaseTypeService_ServiceDesc is the grpc.ServiceDesc for DatabaseTypeService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var DatabaseTypeService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "DatabaseTypeService",
+	HandlerType: (*DatabaseTypeServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "GetDatabaseType",
+			Handler:    _DatabaseTypeService_GetDatabaseType_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "databaseType.proto",
+}
diff --git a/internal/drivers/rpcdriver/getDatabaseType.go b/internal/drivers/rpcdriver/getDatabaseType.go
new file mode 100644
index 0000000..7b8bdd2
--- /dev/null
+++ b/internal/drivers/rpcdriver/getDatabaseType.go
@@ -0,0 +1,47 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package rpcdriver
+
+import (
+	"context"
+	"errors"
+	"schema-orchestrator/internal/drivers/rpcdriver/databaseTypeService"
+
+	"google.golang.org/grpc"
+)
+
+/*
+GetDatabaseType opens a gRPC connection to the user management service and retrieves the database info for the given client and database name
+	clientID: *string, the ID of the client
+	databaseName: *string, the name of the database
+	Return: (*string, error), returns the type of the database and a potential error
+*/
+func (driver *Driver) GetDatabaseType(clientID *string, databaseName *string) (*string, error) {
+	conn, err := grpc.Dial("user-management-service:9000", grpc.WithInsecure())
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+
+	grpcClient := databaseTypeService.NewDatabaseTypeServiceClient(conn)
+
+	response, err := grpcClient.GetDatabaseType(context.Background(), &databaseTypeService.DatabaseTypeRequest{ClientID: *clientID, DatabaseName: *databaseName})
+	if err != nil {
+		return nil, err
+	}
+
+	var databaseType string
+	switch response.DatabaseType {
+	case databaseTypeService.DatabaseTypeResponse_ARANGODB:
+		databaseType = "arangodb"
+	case databaseTypeService.DatabaseTypeResponse_NEO4J:
+		databaseType = "neo4j"
+	default:
+		return nil, errors.New("Unknown database type returned")
+	}
+
+	return &databaseType, nil
+}
diff --git a/internal/drivers/rpcdriver/grpcdriver.go b/internal/drivers/rpcdriver/grpcdriver.go
new file mode 100644
index 0000000..3ebdef0
--- /dev/null
+++ b/internal/drivers/rpcdriver/grpcdriver.go
@@ -0,0 +1,19 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package rpcdriver
+
+/*
+A Driver implements the rpc driver interface
+*/
+type Driver struct {
+}
+
+/*
+New creates a new rpc driver
+*/
+func New() Interface {
+	return &Driver{}
+}
diff --git a/internal/drivers/rpcdriver/interface.go b/internal/drivers/rpcdriver/interface.go
new file mode 100644
index 0000000..0f6fe97
--- /dev/null
+++ b/internal/drivers/rpcdriver/interface.go
@@ -0,0 +1,13 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package rpcdriver
+
+/*
+Interface specifies the methods a rpc driver should implement
+*/
+type Interface interface {
+	GetDatabaseType(clientID *string, databaseName *string) (*string, error)
+}
diff --git a/internal/drivers/webdriver/cors.go b/internal/drivers/webdriver/cors.go
new file mode 100644
index 0000000..49eb1ab
--- /dev/null
+++ b/internal/drivers/webdriver/cors.go
@@ -0,0 +1,20 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package webdriver
+
+import "net/http"
+
+/*
+setupResponse sets up response headers for CORS
+	w: *http.ResponseWriter, writes the responses for http
+	r: *http.Request, sends the requests for http
+*/
+func setupResponse(w *http.ResponseWriter, r *http.Request) {
+	(*w).Header().Set("Access-Control-Allow-Origin", "http://127.0.0.1:3000")
+	(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
+	(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
+	(*w).Header().Set("Access-Control-Allow-Credentials", "true")
+}
diff --git a/internal/drivers/webdriver/executequery.go b/internal/drivers/webdriver/executequery.go
new file mode 100644
index 0000000..5dc2f51
--- /dev/null
+++ b/internal/drivers/webdriver/executequery.go
@@ -0,0 +1,77 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package webdriver
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"schema-orchestrator/internal/entity"
+	"schema-orchestrator/internal/usecases/auth"
+	"schema-orchestrator/internal/usecases/produce"
+
+	"github.com/rs/xid"
+)
+
+/*
+Executes a query handler and returns a http handler
+	authService: auth.UseCase, the usecase for the authentication service
+	produceService: produce.UseCase, the usecase for the producer service
+	Return: http.Handler, returns an http handler
+*/
+func executeQueryHandler(authService auth.UseCase, produceService produce.UseCase) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		// Setup CORS
+		setupResponse(&w, r)
+
+		// Grab sessionID from session-token
+		cookie, cErr := r.Cookie("session-token")
+		if cErr != nil {
+			w.WriteHeader(http.StatusUnauthorized)
+			return
+		}
+
+		cookieValue := &cookie.Value
+
+		valid, sessionID, clientID := authService.Validate(*cookieValue)
+		if !valid {
+			w.WriteHeader(http.StatusUnauthorized)
+			return
+		}
+		log.Println(fmt.Sprintf("Found session cookie for session %v belonging to client %v", *sessionID, *clientID))
+
+		// Generate a unique ID for this query
+		queryID := xid.New().String()
+
+		// Create a response containing the queryID
+		response := entity.QueryID{
+			QueryID: queryID,
+		}
+
+		// Write the encoded result to the http writer
+		json.NewEncoder(w).Encode(response)
+
+		// Publish a message into the query queue
+		body, err := ioutil.ReadAll(r.Body)
+		if err != nil {
+			w.WriteHeader(http.StatusInternalServerError)
+			return
+		}
+
+		// Grab the databaseName from the request
+		var temp map[string]interface{}
+		json.Unmarshal(body, &temp)
+		databaseName, ok := temp["databaseName"].(string)
+		if !ok {
+			w.WriteHeader(http.StatusInternalServerError)
+			return
+		}
+
+		produceService.ProduceQueryExecutionMessage(&body, sessionID, clientID, &databaseName, &queryID)
+	})
+}
diff --git a/internal/drivers/webdriver/interface.go b/internal/drivers/webdriver/interface.go
new file mode 100644
index 0000000..d55ecc9
--- /dev/null
+++ b/internal/drivers/webdriver/interface.go
@@ -0,0 +1,20 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package webdriver
+
+import (
+	"schema-orchestrator/internal/usecases/auth"
+	"schema-orchestrator/internal/usecases/produce"
+	"schema-orchestrator/internal/usecases/retrievequery"
+)
+
+/*
+A ListenerInterface models what a web listener should do
+*/
+type ListenerInterface interface {
+	Start()
+	SetupHandlers(authService auth.UseCase, produceService produce.UseCase, retrieveService retrievequery.UseCase)
+}
diff --git a/internal/drivers/webdriver/retrieveCachedQuery.go b/internal/drivers/webdriver/retrieveCachedQuery.go
new file mode 100644
index 0000000..7edd120
--- /dev/null
+++ b/internal/drivers/webdriver/retrieveCachedQuery.go
@@ -0,0 +1,64 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package webdriver
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+	"schema-orchestrator/internal/entity"
+	"schema-orchestrator/internal/usecases/auth"
+	"schema-orchestrator/internal/usecases/produce"
+	"schema-orchestrator/internal/usecases/retrievequery"
+)
+
+/*
+Retrieves the cached query
+	authService: auth.UseCase, the authentication service
+	retrieveService: retrievequery.UseCase, the retrieval service
+	producerService: produce.UseCase, the producer service
+	Return: http.Handler, returns an http handler
+*/
+func retrieveCachedQuery(authService auth.UseCase, retrieveService retrievequery.UseCase, produceService produce.UseCase) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		// Handle CORS
+		setupResponse(&w, r)
+
+		// Grab sessionID from session-token
+		cookie, cErr := r.Cookie("session-token")
+		if cErr != nil {
+			w.WriteHeader(http.StatusUnauthorized)
+			return
+		}
+
+		cookieValue := &cookie.Value
+
+		valid, sessionID, clientID := authService.Validate(*cookieValue)
+		if !valid {
+			w.WriteHeader(http.StatusUnauthorized)
+			return
+		}
+		log.Println(fmt.Sprintf("Found session cookie for session %v belonging to client %v", *sessionID, *clientID))
+
+		var cachedQueryRequest entity.RetrieveCachedQuery
+		err := json.NewDecoder(r.Body).Decode(&cachedQueryRequest)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusBadRequest)
+			return
+		}
+
+		queryResult, err := retrieveService.RetrieveCachedQuery(sessionID, &cachedQueryRequest.QueryID)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		produceService.ProduceCachedQuery(queryResult, sessionID)
+
+		w.WriteHeader(http.StatusOK)
+	})
+}
diff --git a/internal/drivers/webdriver/web.go b/internal/drivers/webdriver/web.go
new file mode 100644
index 0000000..15ff086
--- /dev/null
+++ b/internal/drivers/webdriver/web.go
@@ -0,0 +1,48 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package webdriver
+
+import (
+	"log"
+	"net/http"
+	"schema-orchestrator/internal/usecases/auth"
+	"schema-orchestrator/internal/usecases/produce"
+	"schema-orchestrator/internal/usecases/retrievequery"
+)
+
+/*
+A Listener is a concrete implementation for a web listener
+*/
+type Listener struct {
+}
+
+/*
+CreateListener creates a web listener
+	Return: *Listener, returns a web listener
+*/
+func CreateListener() *Listener {
+	return &Listener{}
+}
+
+/*
+Start starts the web listener on port 3000
+*/
+func (l *Listener) Start() {
+	log.Println("Started listening on port :3000")
+	http.ListenAndServe(":3000", nil)
+}
+
+/*
+SetupHandlers sets up the web handlers for this listener
+	authService: auth.UseCase, the authentication service
+	produceService: produce.UseCase, the producer service
+	retrieveService: retrievequery.UseCase, the retrieval service
+*/
+func (l *Listener) SetupHandlers(authService auth.UseCase, produceService produce.UseCase, retrieveService retrievequery.UseCase) {
+	log.Println("Setting up handlers")
+	http.HandleFunc("/execute/", executeQueryHandler(authService, produceService).ServeHTTP)
+	http.HandleFunc("/retrieve-cached/", retrieveCachedQuery(authService, retrieveService, produceService).ServeHTTP)
+}
diff --git a/internal/entity/jwt.go b/internal/entity/jwt.go
new file mode 100644
index 0000000..d63bd42
--- /dev/null
+++ b/internal/entity/jwt.go
@@ -0,0 +1,17 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package entity
+
+import "github.com/gbrlsnchs/jwt/v3"
+
+/*
+SessionIDJWTPayload models the payload containing a sessionID
+*/
+type SessionIDJWTPayload struct {
+	jwt.Payload
+	ClientID  string `json:"clientID"`
+	SessionID string `json:"sessionID"`
+}
diff --git a/internal/entity/queryID.go b/internal/entity/queryID.go
new file mode 100644
index 0000000..60dc51f
--- /dev/null
+++ b/internal/entity/queryID.go
@@ -0,0 +1,13 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package entity
+
+/*
+QueryID describes the message sent to the frontend when a new query is executed
+*/
+type QueryID struct {
+	QueryID string `json:"queryID"`
+}
diff --git a/internal/entity/retrieveCachedQueryRequest.go b/internal/entity/retrieveCachedQueryRequest.go
new file mode 100644
index 0000000..c6658f8
--- /dev/null
+++ b/internal/entity/retrieveCachedQueryRequest.go
@@ -0,0 +1,37 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package entity
+
+import (
+	"encoding/json"
+	"errors"
+)
+
+/*
+RetrieveCachedQuery models an incoming cached query request
+*/
+type RetrieveCachedQuery struct {
+	QueryID string `json:"queryID"`
+}
+
+/*
+UnmarshalJSON unmarshals data into the RetrieveCachedQuery struct
+	data: []byte, the data to be unmarshalled
+	Return: error, returns a potential error
+*/
+func (rqr *RetrieveCachedQuery) UnmarshalJSON(data []byte) error {
+	var v map[string]interface{}
+	if err := json.Unmarshal(data, &v); err != nil {
+		return err
+	}
+
+	var valid bool = false
+	if rqr.QueryID, valid = v["queryID"].(string); !valid {
+		return errors.New("missing field 'queryID' or not type 'string'")
+	}
+
+	return nil
+}
diff --git a/internal/usecases/auth/interface.go b/internal/usecases/auth/interface.go
new file mode 100644
index 0000000..8c97814
--- /dev/null
+++ b/internal/usecases/auth/interface.go
@@ -0,0 +1,13 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package auth
+
+/*
+UseCase is an interface describing the JWT uses
+*/
+type UseCase interface {
+	Validate(token string) (bool, *string, *string)
+}
diff --git a/internal/usecases/auth/jwt.go b/internal/usecases/auth/jwt.go
new file mode 100644
index 0000000..afec781
--- /dev/null
+++ b/internal/usecases/auth/jwt.go
@@ -0,0 +1,40 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package auth
+
+import (
+	"log"
+	"os"
+
+	"github.com/gbrlsnchs/jwt/v3"
+)
+
+/*
+Service wraps JWT usecases
+*/
+type Service struct {
+	secret        *string
+	signingSecret *jwt.HMACSHA
+}
+
+/*
+NewService creates a new service
+	Return: *service, returns a new jwt service
+*/
+func NewService() *Service {
+	// Get the JWT signing secret from the environment variables
+	secret := os.Getenv("JWT_SECRET")
+	log.Println(secret)
+
+	// Create signing secret
+	signingSecret := jwt.NewHS256([]byte(secret))
+
+	// Create new service containing the relevant fields
+	return &Service{
+		secret:        &secret,
+		signingSecret: signingSecret,
+	}
+}
diff --git a/internal/usecases/auth/validate.go b/internal/usecases/auth/validate.go
new file mode 100644
index 0000000..f462624
--- /dev/null
+++ b/internal/usecases/auth/validate.go
@@ -0,0 +1,28 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package auth
+
+import (
+	"schema-orchestrator/internal/entity"
+
+	"github.com/gbrlsnchs/jwt/v3"
+)
+
+/*
+Validate checks if a JWT is valid and returns the sessionID and clientID
+	token: string, the token to be validated
+	Return: (bool, *string, *string), if it's a valid bool, and then the session ID, and the client ID.
+*/
+func (s *Service) Validate(token string) (bool, *string, *string) {
+	var payload entity.SessionIDJWTPayload
+	_, err := jwt.Verify([]byte(token), s.signingSecret, &payload)
+
+	if err != nil {
+		return false, nil, nil
+	}
+
+	return true, &payload.SessionID, &payload.ClientID
+}
diff --git a/internal/usecases/produce/interface.go b/internal/usecases/produce/interface.go
new file mode 100644
index 0000000..d97a5b2
--- /dev/null
+++ b/internal/usecases/produce/interface.go
@@ -0,0 +1,14 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package produce
+
+/*
+UseCase is an interface describing the produce usecases
+*/
+type UseCase interface {
+	ProduceQueryExecutionMessage(query *[]byte, sessionID *string, clientID *string, databaseName *string, queryID *string)
+	ProduceCachedQuery(queryResult *[]byte, sessionID *string)
+}
diff --git a/internal/usecases/produce/produce.go b/internal/usecases/produce/produce.go
new file mode 100644
index 0000000..c2807b5
--- /dev/null
+++ b/internal/usecases/produce/produce.go
@@ -0,0 +1,53 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package produce
+
+import (
+	"schema-orchestrator/internal/drivers/rpcdriver"
+
+	"git.science.uu.nl/graphpolaris/broker"
+	"git.science.uu.nl/graphpolaris/keyvaluestore"
+)
+
+/*
+Service wraps consumer methods
+*/
+type Service struct {
+	brokerDriver    broker.Interface
+	requestProducer broker.Producer
+	resultProducer  broker.Producer
+	keyValueStore   keyvaluestore.Interface
+	rpcDriver       rpcdriver.Interface
+}
+
+/*
+NewService creates a new service
+	broker: broker.Interface, the broker for the new service
+	keyValueStore: keyvaluestore.Interface, the key value store for the new service
+	rpcDriver: rpcdriver.Interface, the rpc driver of the new interface
+	Return: *Service, the new service
+*/
+func NewService(broker broker.Interface, keyValueStore keyvaluestore.Interface, rpcDriver rpcdriver.Interface) *Service {
+	return &Service{
+		brokerDriver:  broker,
+		keyValueStore: keyValueStore,
+		rpcDriver:     rpcDriver,
+	}
+}
+
+/*
+Start starts the producer
+*/
+func (s *Service) Start() {
+	// Create producer
+	p := s.brokerDriver.CreateProducer("requests-exchange")
+
+	s.requestProducer = p
+
+	rp := s.brokerDriver.CreateProducer("ui-direct-exchange")
+
+	s.resultProducer = rp
+}
diff --git a/internal/usecases/produce/produceCachedQuery.go b/internal/usecases/produce/produceCachedQuery.go
new file mode 100644
index 0000000..721e471
--- /dev/null
+++ b/internal/usecases/produce/produceCachedQuery.go
@@ -0,0 +1,34 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package produce
+
+import (
+	"context"
+	"fmt"
+	"log"
+
+	"git.science.uu.nl/graphpolaris/keyvaluestore"
+)
+
+/*
+ProduceCachedQuery produces the cached query result
+	queryResult: *[]byte, the query result
+	sessionID: *string, the ID of the session
+*/
+func (s *Service) ProduceCachedQuery(queryResult *[]byte, sessionID *string) {
+	// Use the sessionID to query the key value store to get the queue we need to send this message to
+	clientQueueID, err := s.keyValueStore.Get(context.Background(), *sessionID, keyvaluestore.String)
+	if err != nil || clientQueueID == nil {
+		return
+	}
+
+	log.Println(fmt.Sprintf("Found client queue %s for session %s", clientQueueID, *sessionID))
+
+	headers := make(map[string]interface{})
+	headers["sessionID"] = *sessionID
+	headers["type"] = "queryResult"
+	s.resultProducer.PublishMessage(queryResult, clientQueueID.(string), &headers)
+}
diff --git a/internal/usecases/produce/produceQueryExecutionMessage.go b/internal/usecases/produce/produceQueryExecutionMessage.go
new file mode 100644
index 0000000..5a5245b
--- /dev/null
+++ b/internal/usecases/produce/produceQueryExecutionMessage.go
@@ -0,0 +1,43 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package produce
+
+import "log"
+
+/*
+ProduceQueryExecutionMessage publishes a query execution request
+	query: *[]byte, the query being executed
+	sessionID: *string, the ID of the session
+	clientID: *string, the ID of the client
+	databaseName: *string, the name of the database
+	queryID: *string, the ID of the query
+*/
+func (s *Service) ProduceQueryExecutionMessage(query *[]byte, sessionID *string, clientID *string, databaseName *string, queryID *string) {
+	// Send the message to the correct queue
+	// Request the database type from the user management service
+	databaseType, err := s.rpcDriver.GetDatabaseType(clientID, databaseName)
+	if err != nil {
+		return
+	}
+
+	headers := make(map[string]interface{})
+	headers["sessionID"] = *sessionID
+	headers["clientID"] = *clientID
+	headers["queryID"] = *queryID
+
+	switch *databaseType {
+	case "arangodb":
+		log.Println("Publishing to arangodb queue")
+		s.requestProducer.PublishMessage(query, "arangodb-query-request", &headers)
+	case "neo4j":
+		log.Println("Publishing to neo4j queue")
+		s.requestProducer.PublishMessage(query, "neo4j-query-request", &headers)
+	default:
+		log.Println("No valid database type found")
+		return
+	}
+
+}
diff --git a/internal/usecases/retrievequery/interface.go b/internal/usecases/retrievequery/interface.go
new file mode 100644
index 0000000..094761c
--- /dev/null
+++ b/internal/usecases/retrievequery/interface.go
@@ -0,0 +1,13 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package retrievequery
+
+/*
+UseCase describes method a query retriever service should implement
+*/
+type UseCase interface {
+	RetrieveCachedQuery(sessionID *string, queryID *string) (*[]byte, error)
+}
diff --git a/internal/usecases/retrievequery/retrieveCachedQuery.go b/internal/usecases/retrievequery/retrieveCachedQuery.go
new file mode 100644
index 0000000..8cf93ba
--- /dev/null
+++ b/internal/usecases/retrievequery/retrieveCachedQuery.go
@@ -0,0 +1,34 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package retrievequery
+
+import (
+	"context"
+	"fmt"
+	"io/ioutil"
+	"time"
+)
+
+/*
+RetrieveCachedQuery retrieves a cached query from the object store
+	sessionID: *string, the ID of the session
+	queryID: *string, the ID of the query
+	Return: (*[]byte, error), returns the cached query and an error if there is one
+*/
+func (s *Service) RetrieveCachedQuery(sessionID *string, queryID *string) (*[]byte, error) {
+	getQueryContext, getQueryCancel := context.WithTimeout(context.Background(), time.Second*20)
+	defer getQueryCancel()
+
+	// Get the cached query result from the object store
+	// Query results are stored under the object name sessionID-queryID
+	objectReader, err := s.objectStore.Get(getQueryContext, "cached-queries", fmt.Sprintf("%s-%s", *sessionID, *queryID))
+	if err != nil {
+		return nil, err
+	}
+
+	queryResult, err := ioutil.ReadAll(objectReader)
+	return &queryResult, err
+}
diff --git a/internal/usecases/retrievequery/retrievequery.go b/internal/usecases/retrievequery/retrievequery.go
new file mode 100644
index 0000000..ddcbff2
--- /dev/null
+++ b/internal/usecases/retrievequery/retrievequery.go
@@ -0,0 +1,26 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package retrievequery
+
+import "git.science.uu.nl/graphpolaris/objectstore"
+
+/*
+A Service implements the retrieve query usecase
+*/
+type Service struct {
+	objectStore objectstore.Interface
+}
+
+/*
+NewService creates a new query retrieval service
+	objectStore: objectostore.Interface, the object store for the new service
+	Return: the new service
+*/
+func NewService(objectStore objectstore.Interface) *Service {
+	return &Service{
+		objectStore: objectStore,
+	}
+}
diff --git a/internal/usecases/web/StartListener.go b/internal/usecases/web/StartListener.go
new file mode 100644
index 0000000..1ed4b55
--- /dev/null
+++ b/internal/usecases/web/StartListener.go
@@ -0,0 +1,14 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package web
+
+/*
+StartListener starts the web listener and binds the handlers
+*/
+func (s *Service) StartListener() {
+	// Start the listener
+	s.driver.Start()
+}
diff --git a/internal/usecases/web/interface.go b/internal/usecases/web/interface.go
new file mode 100644
index 0000000..0bdd1e9
--- /dev/null
+++ b/internal/usecases/web/interface.go
@@ -0,0 +1,20 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package web
+
+import (
+	"schema-orchestrator/internal/usecases/auth"
+	"schema-orchestrator/internal/usecases/produce"
+	"schema-orchestrator/internal/usecases/retrievequery"
+)
+
+/*
+UseCase is an interface containing the web usecases
+*/
+type UseCase interface {
+	StartListener()
+	SetupHandlers(authService auth.UseCase, produceService produce.UseCase, retrieveService retrievequery.UseCase)
+}
diff --git a/internal/usecases/web/setuphandlers.go b/internal/usecases/web/setuphandlers.go
new file mode 100644
index 0000000..6a0e60c
--- /dev/null
+++ b/internal/usecases/web/setuphandlers.go
@@ -0,0 +1,22 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package web
+
+import (
+	"schema-orchestrator/internal/usecases/auth"
+	"schema-orchestrator/internal/usecases/produce"
+	"schema-orchestrator/internal/usecases/retrievequery"
+)
+
+/*
+SetupHandlers sets up all handlers in the web driver
+	authService: auth.UseCase, the auth service for the handlers
+	produceService: produce.UseCase, the produce service for the handlers
+	retrieveService: retreievequery.UseCase: the retrieve service for the handlers
+*/
+func (s *Service) SetupHandlers(authService auth.UseCase, produceService produce.UseCase, retrieveService retrievequery.UseCase) {
+	s.driver.SetupHandlers(authService, produceService, retrieveService)
+}
diff --git a/internal/usecases/web/web.go b/internal/usecases/web/web.go
new file mode 100644
index 0000000..c4271a0
--- /dev/null
+++ b/internal/usecases/web/web.go
@@ -0,0 +1,26 @@
+/*
+This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course.
+© Copyright Utrecht University (Department of Information and Computing Sciences)
+*/
+
+package web
+
+import "schema-orchestrator/internal/drivers/webdriver"
+
+/*
+Service wraps all web methods
+*/
+type Service struct {
+	driver webdriver.ListenerInterface
+}
+
+/*
+NewService creates a new web service
+	driver: webdriver.ListenerInterface, the driver for the new service
+	Return: *Service, the new service
+*/
+func NewService(driver webdriver.ListenerInterface) *Service {
+	return &Service{
+		driver: driver,
+	}
+}
-- 
GitLab