Commit 2cfd6f93 authored by Manuel's avatar Manuel

refined rest api

added use-case as field for layers
parent cdc03ca0
## Rabbit MQ
# Rabbit MQ
RABBIT_MQ_HOSTNAME = 'rabbit-mq'
RABBIT_MQ_PORT = 5672
# RABBIT_MQ_HOSTNAME = 'articonf1.itec.aau.at'
# RABBIT_MQ_PORT = 30302
## Trace Retrieval
# Trace Retrieval
TRACE_RETRIEVAL_HOSTNAME = 'trace-retrieval'
TRACE_RETRIEVAL_REST_PORT = 80
TRACE_RETRIEVAL_DB_HOSTNAME = f'{TRACE_RETRIEVAL_HOSTNAME}-db'
TRACE_RETRIEVAL_DB_PORT = 27017
## Semantic Linking
# Semantic Linking
SEMANTIC_LINKING_HOSTNAME = 'semantic-linking'
SEMANTIC_LINKING_REST_PORT = 80
SEMANTIC_LINKING_DB_HOSTNAME = f'{SEMANTIC_LINKING_HOSTNAME}-db'
SEMANTIC_LINKING_DB_PORT = 27017
## Role Stage Discovery
# Role Stage Discovery
ROLESTAGE_DISCOVERY_HOSTNAME = 'role-stage-discovery'
ROLESTAGE_DISCOVERY_REST_PORT = 80
ROLESTAGE_DISCOVERY_DB_HOSTNAME = f'{ROLESTAGE_DISCOVERY_HOSTNAME}-db'
ROLESTAGE_DISCOVERY_DB_PORT = 27017
## Rest Gateway
# REST_GATEWAY_HOSTNAME = 'rest-gateway'
# REST_GATEWAY_DB_HOSTNAME = 'rest-gateway-db'
# Rest Gateway
# REST_GATEWAY_HOSTNAME = 'articonf1.itec.aau.at'
# REST_GATEWAY_DB_HOSTNAME = 'articonf1.itec.aau.at'
REST_GATEWAY_HOSTNAME = 'rest-gateway'
REST_GATEWAY_DB_HOSTNAME = 'rest-gateway-db'
REST_GATEWAY_REST_PORT = 80
REST_GATEWAY_DB_HOSTNAME = f'{REST_GATEWAY_HOSTNAME}-db'
REST_GATEWAY_DB_PORT = 27017
# Business Logic
# BUSINESS_LOGIC_HOSTNAME = 'articonf1.itec.aau.at'
# BUSINESS_LOGIC_DB_HOSTNAME = 'articonf1.itec.aau.at'
BUSINESS_LOGIC_HOSTNAME = 'business-logic'
BUSINESS_LOGIC_DB_HOSTNAME = f'{BUSINESS_LOGIC_HOSTNAME}-db'
# BUSINESS_LOGIC_REST_PORT = 80
# BUSINESS_LOGIC_DB_PORT = 30421
BUSINESS_LOGIC_REST_PORT = 80
BUSINESS_LOGIC_DB_PORT = 27017
......@@ -12,7 +12,44 @@ produces:
basePath: "/api"
paths:
/layers/{name}/cluster-mapping:
/use-case:
delete:
operationId: "routes.layer.delete_uses_cases"
tags:
- "Use-Cases"
summary: "Delete all use-cases"
description: "Delete all use-cases"
responses:
'200':
description: "Successful Request"
get:
operationId: "routes.layer.use_cases"
tags:
- "Use-Cases"
summary: "Retrieves all use-cases"
description: "Retrieves all use-cases"
responses:
'200':
description: "Successful Request"
/use-case/{use_case}/layers:
get:
operationId: "routes.layer.get_all_for_use_case"
tags:
- "Layers"
summary: "Retrieves all layers belonging to the given use-case"
description: "Retrieves all layers belonging to the given use-case"
parameters:
- name: "use_case"
in: "path"
description: "Name of the Use-Case the layer belongs to"
required: true
type: "string"
responses:
'200':
description: "Successful Request"
'404':
description: "Use-Case does not exist"
/use-case/{use_case}/cluster-mapping/layers/{name}:
delete:
operationId: "routes.layer.delete_cluster_mapping"
tags:
......@@ -25,6 +62,11 @@ paths:
description: "Name of the layer (must exist)"
required: true
type: "string"
- name: "use_case"
in: "path"
description: "Name of the Use-Case the layer belongs to"
required: true
type: "string"
- in: body
name: "Object"
required: true
......@@ -54,6 +96,11 @@ paths:
description: "Name of the layer (must exist)"
required: true
type: "string"
- name: "use_case"
in: "path"
description: "Name of the Use-Case the layer belongs to"
required: true
type: "string"
- in: body
name: "Object"
required: true
......@@ -71,7 +118,7 @@ paths:
description: "Layer does not exist"
'400':
description: "Field in request is missing or attribute does not exist in the Layer"
/layers/{name}/mapping:
/use-case/{use_case}/layers/{name}/mapping:
delete:
operationId: "routes.layer.delete_mapping"
tags:
......@@ -84,6 +131,11 @@ paths:
description: "Name of the layer (must exist)"
required: true
type: "string"
- name: "use_case"
in: "path"
description: "Name of the Use-Case the layer belongs to"
required: true
type: "string"
- in: body
name: "Object"
required: true
......@@ -112,6 +164,11 @@ paths:
description: "Name of the layer (must exist)"
required: true
type: "string"
- name: "use_case"
in: "path"
description: "Name of the Use-Case the layer belongs to"
required: true
type: "string"
- in: body
name: "Object"
required: true
......@@ -131,7 +188,7 @@ paths:
description: "Layer does not exist"
'400':
description: "Field in request is missing"
/layers/{name}:
/use-case/{use_case}/layers/{name}:
delete:
operationId: "routes.layer.delete_one"
tags:
......@@ -144,6 +201,11 @@ paths:
description: "Name of the layer to delete"
required: true
type: "string"
- name: "use_case"
in: "path"
description: "Name of the Use-Case the layer belongs to"
required: true
type: "string"
responses:
'200':
description: "Successful Request"
......@@ -161,6 +223,11 @@ paths:
description: "Name of the layer"
required: true
type: "string"
- name: "use_case"
in: "path"
description: "Name of the Use-Case the layer belongs to"
required: true
type: "string"
responses:
'200':
description: "Successful Request"
......@@ -178,6 +245,11 @@ paths:
description: "Name of the new layer"
required: true
type: "string"
- name: "use_case"
in: "path"
description: "Name of the Use-Case the layer belongs to"
required: true
type: "string"
responses:
'200':
description: "Successful Request"
......@@ -195,23 +267,7 @@ paths:
name: "Object"
required: true
schema:
type: object
properties:
name:
type: string
example: "layer1"
cluster_properties:
type: array
items:
type: string
example: "internal_property_1"
properties:
type: object
additionalProperties:
type: string
example:
"internal_property_1": "external_property_1"
"internal_property_2": "external_property_2"
$ref: '#/definitions/LayerAdapter'
responses:
'200':
description: "Successful Request"
......@@ -243,3 +299,31 @@ paths:
responses:
'200':
description: "Successful echo of request data"
definitions:
LayerAdapter:
type: "object"
required:
- name
- use_case
- cluster_properties
- properties
properties:
name:
type: string
example: "layer1"
use_case:
type: string
example: "car-sharing"
cluster_properties:
type: array
items:
type: string
example: "internal_property_1"
properties:
type: object
additionalProperties:
type: string
example:
"internal_property_1": "external_property_1"
"internal_property_2": "external_property_2"
\ No newline at end of file
......@@ -7,7 +7,7 @@ class LayerAdapter:
attributes from the dataset correspond to each one
'''
def __init__(self, name: str, properties: Dict[str, str], cluster_properties: List[str]):
def __init__(self, name: str, use_case: str, properties: Dict[str, str], cluster_properties: List[str]):
'''
Creates a new instance of LayerAdapter
......@@ -15,9 +15,11 @@ class LayerAdapter:
name - Required : unique identifier for the layer
properties - Required : maps InternalPropertyName->DatasetPropertyName
cluster_properties - Required : subset of the keys of properties, marks properties to cluster with
use_case - Required : identifier for the use-case this layer belongs to
'''
self.name = name
self.properties = properties
self.use_case = use_case
for prop in cluster_properties:
if prop not in properties.keys():
......@@ -82,13 +84,22 @@ class LayerAdapter:
return {
"name": self.name,
"properties": self.properties,
"cluster_properties": self.cluster_properties
"cluster_properties": self.cluster_properties,
"use_case": self.use_case
}
@staticmethod
def from_serializable_dict(user_dict: Dict):
'''
creates a layer object from a dictionary. has to have the following keys:
- name
- properties
- cluster_properties
- use_case
'''
return LayerAdapter(
user_dict["name"],
user_dict["use_case"],
user_dict["properties"],
user_dict["cluster_properties"]
)
from typing import Dict, List
class UseCase:
'''
represents the mapping from an internal layer with a set of attributes and what
attributes from the dataset correspond to each one
'''
def __init__(self, name: str):
'''
Creates a new instance of LayerAdapter
@params:
name - Required : unique identifier for the layer
properties - Required : maps InternalPropertyName->DatasetPropertyName
cluster_properties - Required : subset of the keys of properties, marks properties to cluster with
use_case - Required : identifier for the use-case this layer belongs to
'''
self.name = name
def to_serializable_dict(self) -> Dict:
return {
"name": self.name,
}
@staticmethod
def from_serializable_dict(user_dict: Dict):
'''
creates a layer object from a dictionary. has to have the following keys:
- name
- properties
- cluster_properties
- use_case
'''
return UseCase(
user_dict["name"],
)
......@@ -2,10 +2,11 @@
import network_constants as netconst
from database.MongoRepositoryBase import MongoRepositoryBase
from db.entities.layer_adapter import LayerAdapter
from db.entities.use_case import UseCase
import pymongo
import json
from typing import List
from typing import List, Dict
class Repository(MongoRepositoryBase):
'''This is a repository for MongoDb.'''
......@@ -16,22 +17,55 @@ class Repository(MongoRepositoryBase):
'rest-gateway-db')
self._adapter_collection = 'layer_adapters'
self._use_case_collection = 'use_cases'
def delete_all_use_cases_with_name(self, name: str):
collection = self._database[self._use_case_collection]
collection.delete_many({"name": name})
def delete_all_layers(self):
collection = self._database[self._adapter_collection]
collection.delete_many({})
def delete_all_use_cases(self):
collection = self._database[self._use_case_collection]
collection.delete_many({})
def all_use_cases(self) -> List[UseCase]:
dicts = list(super().get_entries(self._use_case_collection, projection={'_id': False}))
return [UseCase.from_serializable_dict(d) for d in dicts]
def put_use_case(self, use_case_name: str):
use_cases = self.all_use_cases()
existing_use_cases = list(filter(lambda use_case: use_case.name == use_case_name, use_cases))
if len(existing_use_cases) == 0:
use_case = UseCase(use_case_name)
super().insert_entry(self._use_case_collection, use_case.to_serializable_dict())
def add(self, adapter : LayerAdapter):
self.put_use_case(adapter.use_case)
super().insert_entry(self._adapter_collection, adapter.to_serializable_dict())
def one_by_name(self, name : str) -> LayerAdapter:
return list(super().get_entries(self._adapter_collection, selection={"name": name}))
def one_by_name_and_usecase(self, name : str, use_case: str) -> LayerAdapter:
return list(super().get_entries(self._adapter_collection, selection={"name": name, "use_case": use_case}))
def update(self, adapter : LayerAdapter):
collection = self._database[self._adapter_collection]
collection.update_one({"name":adapter.name}, {"$set": adapter.to_serializable_dict()})
collection.update_one({"name":adapter.name, "use_case": adapter.use_case}, {"$set": adapter.to_serializable_dict()})
def delete_all_with_name(self, name: str):
def delete_all_with_name_and_use_case(self, name: str, use_case: str):
collection = self._database[self._adapter_collection]
collection.delete_many({"name": name})
collection.delete_many({"name": name, "use_case": use_case})
def all(self) -> List[LayerAdapter]:
def all(self) -> List[Dict]:
result = super().get_entries(self._adapter_collection, projection={'_id': False})
return list(result)
def all_for_use_case(self, use_case: str) -> Dict:
result = super().get_entries(self._adapter_collection, projection={'_id': False}, selection={"use_case": use_case})
return list(result)
\ No newline at end of file
......@@ -5,20 +5,32 @@ from services.layer_adapter_service import LayerAdapterService
import json
from flask import Response, request
def use_cases():
return [adapter.to_serializable_dict() for adapter in LayerAdapterService.all_use_cases()]
def delete_uses_cases():
LayerAdapterService.delete_all_use_cases()
return Response(status=200)
def all():
return LayerAdapterService.all()
def add(name:str):
def get_all_for_use_case(use_case: str):
return LayerAdapterService.all_for_use_case(use_case)
def add(name: str, use_case: str):
'''
add an empty layer to the DB
@params:
name - Required : unique identifier for the layer
name - Required : unique identifier for the layer
use_case - Required : String-identifier for the use-case
'''
if LayerAdapterService.one(name) != None:
if LayerAdapterService.one(name, use_case) != None:
return Response(status=400, response=f"Layer with name '{name}' already exists!")
LayerAdapterService.add(name)
LayerAdapterService.add(name, use_case)
return Response(status=200)
def add_complete():
......@@ -27,74 +39,81 @@ def add_complete():
'''
data = request.json
if "name" not in data or "properties" not in data or "cluster_properties" not in data:
if "name" not in data or "properties" not in data or "cluster_properties" not in data or "use_case" not in data:
return Response(status=400, response=f"Field missing! Fields required: (name, properties, cluster_properties)")
layer = LayerAdapterService.one(data["name"])
layer = LayerAdapterService.one(data["name"], data["use_case"])
if layer != None:
return Response(status=400, response=f'Layer with name "{data["name"]}" already exists!')
try:
layer_new = LayerAdapter.from_serializable_dict(data)
LayerAdapterService.add_complete(layer_new)
return Response(status=200)
except:
except BaseException as e:
print(f"Exception: {e}")
return Response(status=400)
def one(name:str):
def one(name: str, use_case: str):
'''
fetch a single layer from the DB
@params:
name - Required : unique identifier for the layer
name - Required : unique identifier for the layer
use_case - Required : String-identifier for the use-case
'''
layer = LayerAdapterService.one(name)
layer = LayerAdapterService.one(name, use_case)
if layer == None:
return Response(status=404, response=f"Layer with name '{name}' does not exist!")
return Response(status=200, response=json.dumps(layer.to_serializable_dict()))
def add_mapping(name:str):
def add_mapping(name: str, use_case: str):
'''
add a new mapping to the layer identified by name
@params:
name - Required : unique identifier for the layer
name - Required : unique identifier for the layer
use_case - Required : String-identifier for the use-case
'''
layer = LayerAdapterService.one(name)
layer = LayerAdapterService.one(name, use_case)
if layer == None:
return Response(status=404, response=f"Layer with name '{name}' does not exist!")
data = request.json
if "internal" not in data or "external" not in data:
return Response(status=400, response=f"Field missing! Fields required: (internal, external)")
layer.add_mapping(data["internal"], data["external"])
LayerAdapterService.update(layer)
return Response(status=200)
def delete_mapping(name:str):
def delete_mapping(name: str, use_case: str):
'''
delete a mapping from the layer identified by name
@params:
name - Required : unique identifier for the layer
name - Required : unique identifier for the layer
use_case - Required : String-identifier for the use-case
'''
layer = LayerAdapterService.one(name)
layer = LayerAdapterService.one(name, use_case)
if layer == None:
return Response(status=404, response=f"Layer with name '{name}' does not exist!")
data = request.json
if "internal" not in data:
return Response(status=400, response=f"Field missing! Fields required: (internal)")
try:
layer.delete_mapping(data["internal"])
LayerAdapterService.update(layer)
......@@ -103,23 +122,25 @@ def delete_mapping(name:str):
return Response(status=200)
def add_cluster_mapping(name:str):
def add_cluster_mapping(name: str, use_case: str):
'''
add a mapped property to the list of properties to cluster with
@params:
name - Required : unique identifier for the layer
name - Required : unique identifier for the layer
use_case - Required : String-identifier for the use-case
'''
layer = LayerAdapterService.one(name)
layer = LayerAdapterService.one(name, use_case)
if layer == None:
return Response(status=404, response=f"Layer with name '{name}' does not exist!")
data = request.json
if "attribute" not in data:
return Response(status=400, response=f"Field missing! Fields required: (attribute)")
try:
layer.add_cluster_mapping(data["attribute"])
LayerAdapterService.update(layer)
......@@ -127,23 +148,25 @@ def add_cluster_mapping(name:str):
except:
return Response(status=400, response=f'{data["attribute"]} is no attribute in the layer!')
def delete_cluster_mapping(name:str):
def delete_cluster_mapping(name: str, use_case: str):
'''
remove a mapped property from the list of properties to cluster with
@params:
name - Required : unique identifier for the layer
name - Required : unique identifier for the layer
use_case - Required : String-identifier for the use-case
'''
layer = LayerAdapterService.one(name)
layer = LayerAdapterService.one(name, use_case)
if layer == None:
return Response(status=404, response=f"Layer with name '{name}' does not exist!")
data = request.json
if "attribute" not in data:
return Response(status=400, response=f"Field missing! Fields required: (attribute)")
try:
layer.delete_cluster_mapping(data["attribute"])
LayerAdapterService.update(layer)
......@@ -152,17 +175,19 @@ def delete_cluster_mapping(name:str):
print(e)
return Response(status=400, response=f'{data["attribute"]} is no attribute in the layer!')
def delete_one(name:str):
def delete_one(name: str, use_case: str):
'''
delete a layer and all its mappings from the Db
@params:
name - Required : unique identifier for the layer
name - Required : unique identifier for the layer
use_case - Required : String-identifier for the use-case
'''
layer = LayerAdapterService.one(name)
layer = LayerAdapterService.one(name, use_case)
if layer == None:
return Response(status=404, response=f"Layer with name '{name}' does not exist!")
LayerAdapterService.delete(layer)
return Response(status=200)
\ No newline at end of file
return Response(status=200)
......@@ -9,12 +9,32 @@ class LayerAdapterService:
_repository = Repository()
@staticmethod
def all_use_cases() -> List[str]:
return LayerAdapterService._repository.all_use_cases()
@staticmethod
def delete_all_use_cases():
LayerAdapterService._repository.delete_all_use_cases()
@staticmethod
def delete_use_case(name:str):
LayerAdapterService._repository.delete_all_use_cases_with_name(name)
@staticmethod
def all() -> List[LayerAdapter]:
'''
Return all currently defined layers
'''
return LayerAdapterService._repository.all()
@staticmethod
def all_for_use_case(use_case: str) -> List[LayerAdapter]:
'''
Return all currently defined layers that belong to the
given use-case
'''
return LayerAdapterService._repository.all_for_use_case(use_case)
@staticmethod
def update(layer: LayerAdapter):
......@@ -28,15 +48,16 @@ class LayerAdapterService:
LayerAdapterService._repository.update(layer)
@staticmethod
def add(name: str):
def add(name: str, use_case: str):
'''
Add a new layer to the DB. Attribute mapping and cluster
attributes will be empty per default
@params:
name - Required : Unique name for a layer.
name - Required : Unique name for a layer.
use_case - Required : String-identifier for the use-case
'''
adapter_new = LayerAdapter(name, {}, [])
adapter_new = LayerAdapter(name, use_case, {}, [])
LayerAdapterService._repository.add(adapter_new)
......@@ -59,18 +80,25 @@ class LayerAdapterService:
@params:
layer - Required : layer object to remove from the DB
'''
LayerAdapterService._repository.delete_all_with_name(layer.name)
use_case = layer.use_case
LayerAdapterService._repository.delete_all_with_name_and_use_case(layer.name, use_case)
# remove use-case if it is not needed
layers_in_use_case = LayerAdapterService.all_for_use_case(use_case)
if len(layers_in_use_case) == 0:
LayerAdapterService.delete_use_case(use_case)
@staticmethod
def one(name: str) -> LayerAdapter:
def one(name: str, use_case: str) -> LayerAdapter:
'''
Retrieve a single layer from the DB. Returns None if no layer
was found under this name.
@params:
name - Required : Unique name for a layer.
name - Required : Unique name for a layer
use_case - Required : String-identifier for the use-case
'''
result = LayerAdapterService._repository.one_by_name(name)
result = LayerAdapterService._repository.one_by_name_and_usecase(name, use_case)
if len(result) == 1:
return LayerAdapter.from_serializable_dict(result[0])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment