diff --git a/README.md b/README.md
index d0ada772b4b1bc1b02a7fed91e5a7d1319914d02..b5322bbdae69e6ccceee5fdd54e6a727d8135d27 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 [![Build](https://git-ce.rwth-aachen.de/wzl-mq-ms/forschung-lehre/lava/unified-device-interface/python/badges/master/pipeline.svg)](https://git-ce.rwth-aachen.de/wzl-mq-ms/forschung-lehre/lava/unified-device-interface/python/commits/master)
 
 # Python Unified Device Interface
-Current stable version: 9.0.1
+Current stable version: 9.1.0
 
 ## Installation
 1. Install the WZL-UDI package via pip
@@ -58,6 +58,9 @@ Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation)
 
 ## Recent changes
 
+**9.1.0** - 2024-01-17
+  - the license for profiles, metadata and data is now provided anc can be specified in the config file
+
 **9.0.1** - 2024-01-11
   - bug fix of semantic name resolution
 
diff --git a/setup.py b/setup.py
index d8f626c49704e3c30932d62cf35744972db93afa..dc65d013ff37a9c79cee347c635d746927d6c5e8 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
     long_description = fh.read()
 
 setup(name='wzl-udi',
-      version='9.0.1',
+      version='9.1.0',
       url='https://git-ce.rwth-aachen.de/wzl-mq-public/soil/python',
       project_urls={
           "Bug Tracker": "https://git-ce.rwth-aachen.de/wzl-mq-public/soil/python/-/issues",
diff --git a/src/soil/component.py b/src/soil/component.py
index daca80dfe5916dc8c46d7f3082456b57678efdc3..4767d0f8b50d8a3e62e9f3fa3ccbd9431eee2f88 100644
--- a/src/soil/component.py
+++ b/src/soil/component.py
@@ -19,7 +19,7 @@ from .error import ChildNotFoundException
 from .function import Function
 from .measurement import Measurement
 from .parameter import Parameter
-from .semantics import Namespaces
+from .semantics import Namespaces, Semantics
 from ..utils import root_logger
 from ..utils.constants import HTTP_GET
 from ..utils.error import SerialisationException, DeviceException, UserException
@@ -399,12 +399,22 @@ class Component(Element):
         try:
             return super().resolve_semantic_path(suffix)
         except ChildNotFoundException:
+            # check if the path fits one of the components children
             for child in self.children:
                 try:
                     return child.resolve_semantic_path(suffix)
                 except ChildNotFoundException:
                     continue
 
+            # check if the profile of this component imports a shape which matches the path
+            imported_profiles = list(self._metadata_profile.objects(predicate=Namespaces.owl.imports))
+            for imported_profile in imported_profiles:
+                if imported_profile.toPython().replace(Semantics.namespace, '') == suffix:
+                    # TODO implement loading and returning of the base components profile
+                    #  (is not present as element, so might require adaption of the method signature,
+                    #  might also be called recursively, if the base component has own bases which are queried)
+                    raise ChildNotFoundException('Profiles of base components can currently not be returned.')
+
             raise ChildNotFoundException('Could not resolve the semantic path.')
 
     @property
diff --git a/src/soil/element.py b/src/soil/element.py
index cf0c30ac6fe1e429c38151fea50381d8f961a75a..833b7dbfd3fe85b0b931f72e452d665701574dc2 100644
--- a/src/soil/element.py
+++ b/src/soil/element.py
@@ -6,6 +6,7 @@ from typing import Any, Dict, List
 import rdflib
 
 from .error import ChildNotFoundException
+from .semantics import Namespaces, Semantics
 from ..utils.constants import BASE_UUID_PATTERN, HTTP_GET
 from ..utils.error import SerialisationException
 
@@ -101,12 +102,15 @@ class Element(ABC):
         shape_filename = os.path.join(profiles_path, f"{self._profilename}.shacl.ttl")
         self._metadata_profile = rdflib.Graph()
         self._metadata_profile.parse(shape_filename)
+        self._metadata_profile.add((rdflib.URIRef(Semantics.namespace[self._profilename]), Namespaces.dcterms.license,
+                                    Semantics.profile_license))
 
         # load metadata
         self._semantic_name = f'{parent_name}{self.uuid[4:].capitalize()}'
         metadata_filename = os.path.join(metadata_path, f"{self._semantic_name}.ttl")
         self._metadata = rdflib.Graph()
         self._metadata.parse(metadata_filename)
+        self._metadata.add((rdflib.URIRef(self._semantic_name), Namespaces.schema.license, Semantics.metadata_license))
 
     @abstractmethod
     def serialize_semantics(self, kind: str) -> rdflib.Graph:
diff --git a/src/soil/measurement.py b/src/soil/measurement.py
index 217f46fac3b67d4ad4db2e315a9d080d3dee7a25..6624efad9717fd88de106f396f5699ff5bb34cd9 100644
--- a/src/soil/measurement.py
+++ b/src/soil/measurement.py
@@ -197,6 +197,7 @@ class Measurement(Figure):
             data_graph.add((observation_subject, Namespaces.sosa.hasResult,
                             Semantics.namespace[f'{self._semantic_name}Measurement']))
             data_graph.add((observation_subject, Namespaces.sosa.madeBySensor, sensor_triples[0][2]))
+            data_graph.add((observation_subject, Namespaces.schema.license, Semantics.data_license))
 
             # create result node
             unit_triples = list(self._metadata.triples((None, Namespaces.qudt.applicableUnit, None)))
@@ -207,6 +208,7 @@ class Measurement(Figure):
             data_graph.add((measurement_subject, Namespaces.rdf.type, rdflib.URIRef(Namespaces.soil.Measurement)))
             data_graph.add((measurement_subject, Namespaces.sosa.isResultOf, observation_subject))
             data_graph.add((measurement_subject, Namespaces.qudt.unit, unit_triples[0][2]))
+            data_graph.add((measurement_subject, Namespaces.schema.license, Semantics.data_license))
 
             rdf_value = Figure.serialize_value(data_graph, self.__getitem__('value', 0))
 
diff --git a/src/soil/semantics.py b/src/soil/semantics.py
index 00a59c6d053a81e880a847a83009167bfbad3e1a..7a3f80159afb64a0937ab0064295ad9b6e0bc17d 100644
--- a/src/soil/semantics.py
+++ b/src/soil/semantics.py
@@ -1,19 +1,44 @@
+import re
+import urllib
+
 import rdflib
 
+from ..utils.constants import URL_PATTERN
+
 
 class Semantics(object):
     prefix: str = None
     url: str = None
     namespace: rdflib.Namespace = None
+    profile_license: rdflib.term.Identifier = rdflib.URIRef("https://spdx.org/licenses/CC-BY-4.0.html")
+    metadata_license: rdflib.term.Identifier = rdflib.URIRef("https://spdx.org/licenses/CC-BY-NC-ND-4.0.html")
+    data_license: rdflib.term.Identifier = rdflib.Literal("All rights reserved.")
 
     def __init__(self, config: dict[str, str]):
         Semantics.prefix = config['prefix']
         Semantics.url = config['url']
         Semantics.namespace = rdflib.Namespace(config['url'])
+        if 'profile-license' in config:
+            if re.match(URL_PATTERN, config['profile-license']):
+                Semantics.profile_license = rdflib.URIRef(config['profile-license'])
+            else:
+                Semantics.profile_license = rdflib.Literal(config['profile-license'])
+        if 'metadata-license' in config:
+            if re.match(URL_PATTERN, config['metadata-license']):
+                Semantics.metadata_license = rdflib.URIRef(config['metadata-license'])
+            else:
+                Semantics.metadata_license = rdflib.Literal(config['metadata-license'])
+        if 'data-license' in config:
+            if re.match(URL_PATTERN, config['data-license']):
+                Semantics.data_license = rdflib.URIRef(config['data-license'])
+            else:
+                Semantics.data_license = rdflib.Literal(config['data-license'])
 
 
 class Namespaces(object):
+    dcterms = rdflib.namespace.DCTERMS
     m4i = rdflib.Namespace('http://w3id.org/nfdi4ing/metadata4ing#')
+    owl = rdflib.Namespace('http://www.w3.org/2002/07/owl#')
     quantitykind = rdflib.Namespace('http://qudt.org/vocab/quantitykind/')
     qudt = rdflib.Namespace('http://qudt.org/schema/qudt/')
     rdf = rdflib.namespace.RDF
diff --git a/src/soil/stream.py b/src/soil/stream.py
index 8675e012641d34a450f1679d5370e1b4e7dd8147..0330d8634222c3f39aded671cef7ad53473fe360 100644
--- a/src/soil/stream.py
+++ b/src/soil/stream.py
@@ -124,7 +124,7 @@ class Job(ABC):
         try:
             url, data = self._retrieve_semantic_metadata(model)
             measurement_subject = \
-            list((data.subjects(predicate=Namespaces.rdf.type, object=Namespaces.soil.Measurement)))[0]
+                list((data.subjects(predicate=Namespaces.rdf.type, object=Namespaces.soil.Measurement)))[0]
 
             # replace value
             data.remove((None, Namespaces.qudt.value, None))
@@ -298,6 +298,7 @@ class StreamScheduler(object):
                         # try to send semantic data package
                         try:
                             url, semantic_data = job.semantic_data(self._model)
+                            url = url.replace('https://', '').replace('http://', '')
                             if self._dataformat == 'json':
                                 message = semantic_data.serialize(format='json-ld')
                             elif self._dataformat == 'xml':
diff --git a/src/utils/constants.py b/src/utils/constants.py
index 8ac340e21bace0baf074d4049a6729365a00868b..6865dd0ba1b4bac41eeb87050fc23f69c050e9af 100644
--- a/src/utils/constants.py
+++ b/src/utils/constants.py
@@ -1,3 +1,13 @@
+import re
+
 HTTP_GET = 0
 HTTP_OPTIONS = 1
-BASE_UUID_PATTERN = r'[0-9A-Za-z-_]{3,}'
\ No newline at end of file
+BASE_UUID_PATTERN = r'[0-9A-Za-z-_]{3,}'
+
+URL_PATTERN = re.compile(
+    r'^(?:http|ftp)s?://'  # http:// or https://
+    r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'  # domain...
+    r'localhost|'  # localhost...
+    r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
+    r'(?::\d+)?'  # optional port
+    r'(?:/?|[/?]\S+)$', re.IGNORECASE)