Fixed Find server URLs, AdaptDataService demo, support for new
authorjani <jani@asema.com>
Fri, 2 Aug 2019 07:16:44 +0000 (10:16 +0300)
committerjani <jani@asema.com>
Fri, 2 Aug 2019 07:16:44 +0000 (10:16 +0300)
properties in Python classes

12 files changed:
Common/C#/SmartAPI/common/URLs.cs
Common/C++/SmartAPI/smartapi/common/URLs.h
Common/Java/SmartAPI/src/smartapi/common/URLs.java
Common/Python/SmartAPI/agents/RegistrationAgent.py
Common/Python/SmartAPI/common/RESOURCE.py
Common/Python/SmartAPI/common/Tools.py
Common/Python/SmartAPI/common/URLs.py
Common/Python/SmartAPI/model/Activity.py
Common/Python/SmartAPI/model/Authorization.py [new file with mode: 0644]
Common/Python/SmartAPI/model/Entity.py
Common/Python/SmartAPI/model/Obj.py
Examples/Python/AdaptDataService/AdaptDataService.py [new file with mode: 0755]

index 9495367e95c01f74cee01532d0c19cbf93b07ae6..7c4ea4bc11195c70993a9b5b0b6c84e2268dd233 100644 (file)
@@ -10,8 +10,8 @@ namespace SmartAPI.Common
     {
         // Smart API Find
         public const String FIND_HOST_URI = "http://find.smart-api.io/";
-           public const String FIND_URI = URLs.FIND_HOST_URI + "rs/smartapi/v1.0e1.0/access";
-           public const String FIND_KEY_URI = URLs.FIND_HOST_URI + "rs/key";
+           public const String FIND_URI      = URLs.FIND_HOST_URI + "smart/v1.0e1.0/access";
+           public const String FIND_KEY_URI  = URLs.FIND_HOST_URI + "smart/v1.0e1.0/key";
        
            // Smart API Talk
            public const String TALK_HOST_URI = "http://talk.smart-api.io/";
index 08d468d38c8a5dba6387230eb5123cca90375d09..051409f0af82a73545c7a6ba409296158adb3006 100644 (file)
@@ -3,10 +3,10 @@
 
 #define REFERENCE_URI_PREFIX                                                           "http://smart-api.io/reference/1.0/smartapi#"
 
-#define SMARTAPI_REGISTER_SEARCH_URI                                           "http://find.smart-api.io/rs/search"
-#define SMARTAPI_REGISTER_URI                                                          "http://find.smart-api.io/rs/register"
-#define SMARTAPI_REGISTER_SHARING_URI                                          "http://find.smart-api.io/rs/sharing"
-#define SMARTAPI_REGISTER_KEY_URI                                                      "http://find.smart-api.io/rs/key"
+#define SMARTAPI_REGISTER_SEARCH_URI                                           "http://find.smart-api.io/smart/v1.0e1.0/access"
+#define SMARTAPI_REGISTER_URI                                                          "http://find.smart-api.io/smart/v1.0e1.0/access"
+#define SMARTAPI_REGISTER_SHARING_URI                                          "http://find.smart-api.io/smart/v1.0e1.0/access"
+#define SMARTAPI_REGISTER_KEY_URI                                                      "http://find.smart-api.io/smart/v1.0e1.0/key"
 
 #define SMARTAPI_TRANSACTION_URI                                                       "http://transact.smart-api.io/smart/v1.0e1.0"
 #define SMARTAPI_SECURE_URI                                                                    "http://secure.smart-api.io"
index ffaaaa6c06e2f872a6e42738839eac2ae8aaf6bb..9dfd6f126296e0b828270f0ed533c8ca064214de 100644 (file)
@@ -4,8 +4,8 @@ public final class URLs {
 
        // Smart API Find
        public static final String FIND_HOST_URI = "http://find.smart-api.io/";
-       public static final String FIND_URI = URLs.FIND_HOST_URI + "rs/smartapi/v1.0e1.0/access";
-       public static final String FIND_KEY_URI = URLs.FIND_HOST_URI + "rs/key";
+       public static final String FIND_URI      = URLs.FIND_HOST_URI + "smart/v1.0e1.0/access";
+       public static final String FIND_KEY_URI  = URLs.FIND_HOST_URI + "smart/v1.0e1.0/key";
        
        // Smart API Talk
        public static final String TALK_HOST_URI = "http://talk.smart-api.io/";
index 562d3355c587ccd7bc7f0a69fde2c6c8d8c2cde5..274bbaaee5957d389f35a3c27c364235595d06db 100755 (executable)
@@ -29,7 +29,7 @@ class RegistrationAgent(Agent):
         self.timestamp = None # timestamp of the sent registration request
         self.entities = [] # list of entities to be registered
         self.serialization = SERIALIZATION.TURTLE # rdf serialization of the registration message
-        self.debug = True
+        self.debug = False
         self.locked = False # switch to mark registration as locked so others cannot overwrite
         self.serverAddress = FIND_URI  # uri of the SMARTAPI registration service
     
@@ -112,7 +112,7 @@ class RegistrationAgent(Agent):
             traceback.print_exc()
             return None, None
 
-        messageBody, contentType = Tools.serializeRequest(request)
+        messageBody, contentType = Tools.serializeRequest(request, printDebug=self.debug)
        
         if self.debug:
             print "\nRegistration request:"
index c161dd49917320f868c4fb516ac4e488c6a08aa4..df83e62aa5223b06369de3f8dc52d80a6425fe6b 100644 (file)
@@ -1967,3 +1967,8 @@ class RESOURCE(object):
        ZONEPOPULATIONDEPENDENTPRICESPECIFICATION = "http://smart-api.io/ontology/1.0/smartapi#ZonePopulationDependentPriceSpecification"
        ZONETRAVELDEPENDENTPRICESPECIFICATION = "http://smart-api.io/ontology/1.0/smartapi#ZoneTravelDependentPriceSpecification"
        ZONETRAVELDURATIONDEPENDENTPRICESPECIFICATION = "http://smart-api.io/ontology/1.0/smartapi#ZoneTravelDurationDependentPriceSpecification"
+       
+       COOKIE = "http://smart-api.io/ontology/1.0/smartapi#Cookie"
+       HTTPSTANDARD = "http://smart-api.io/ontology/1.0/smartapi#HttpStandard"
+       OAUTH2 = "http://smart-api.io/ontology/1.0/smartapi#OAuth2"
+
index eb251328e0ea860df93ab11789068d8957ebe0c8..593b0c56255c2aea699e1c45e6a6f9230b5c00d9 100644 (file)
@@ -438,34 +438,34 @@ class Tools(object):
                print '*  ------   ERROR   ------  *'
        
        @classmethod
-       def serializeNotification(cls, message, serialization = 'text/turtle', noHeader=True):
+       def serializeNotification(cls, message, serialization = 'text/turtle', noHeader=True, printDebug=False):
                '''
                '''
-               return cls.serializeMessage(message, serialization, noHeader)
+               return cls.serializeMessage(message, serialization, noHeader, printDebug)
                
        
        @classmethod
-       def serializeRequest(cls, message, serialization = SERIALIZATION.TURTLE, noHeader=True):
+       def serializeRequest(cls, message, serialization = SERIALIZATION.TURTLE, noHeader=True, printDebug=False):
                '''
                @see  serializeMessage
                @param message: Request Object
                @param serialization:  
                @param noHeader: true if MIME headers are stripped. useful when sending out through HTTP POST
                '''
-               return cls.serializeMessage(message, serialization, noHeader)
+               return cls.serializeMessage(message, serialization, noHeader, printDebug)
        
        @classmethod
-       def serializeResponse(cls, message, serialization = SERIALIZATION.TURTLE, noHeader=True):
+       def serializeResponse(cls, message, serialization = SERIALIZATION.TURTLE, noHeader=True, printDebug=False):
                '''
                @see  serializeMessage
                @param message: Response Object
                @param serialization: 
                @param noHeader: true if MIME headers are stripped, useful when sending out through HTTP POST
                '''
-               return cls.serializeMessage(message, serialization, noHeader)
+               return cls.serializeMessage(message, serialization, noHeader, printDebug)
        
        @classmethod
-       def serializeMessage(cls, message, serialization = SERIALIZATION.TURTLE, noHeader=True):
+       def serializeMessage(cls, message, serialization = SERIALIZATION.TURTLE, noHeader=True, printDebug=False):
                '''              
                Extended version of Tools.toString() method. This method takes a Request or Response Object as input, 
                return MIME message (multipart or single part). 
@@ -478,17 +478,21 @@ class Tools(object):
                , decided by 'noHeader' parameter
                the other string is the Content-Type header
                '''
-               message = cls.serializeAsMessage(message, serialization)
+               message = cls.serializeAsMessage(message, serialization, printDebug=printDebug)
                messagePayload = message.asStringCRLF()
                if noHeader:
                        messagePayload = cls._stripMIMEheaders(messagePayload)
                return (messagePayload, message.getContentType())
        
        @classmethod
-       def serializeAsMessage(cls, message, serialization = SERIALIZATION.TURTLE):
+       def serializeAsMessage(cls, message, serialization = SERIALIZATION.TURTLE, printDebug=False):
                Tools.messageParts.clear()
-               # this step might add new items to Tools.messageParts.                                  
+               # this step might add new items to Tools.messageParts.
                messageString = cls.toString(message, serialization)
+               
+               if printDebug:
+                       print messageString
+               
                # multipart or single part generation goes here.                
                if len(Tools.messageParts) == 0:
                        httpMessageSingle = HttpMessageSingle()
index 4758012aaebed658aac8a755dbe87ac863feee0c..be646905a1228d8e9d1410983e31a97a83544960 100644 (file)
@@ -2,8 +2,8 @@ SMARTAPI_HOST_URI           = "http://smart-api.io/"
 
 # FIND
 FIND_HOST_URI               = "http://find.smart-api.io/"
-FIND_URI                    = FIND_HOST_URI + "rs/smartapi/v1.0e1.0/access"
-FIND_KEY_URI                = FIND_HOST_URI + "rs/key"
+FIND_URI                    = FIND_HOST_URI + "smart/v1.0e1.0/access"
+FIND_KEY_URI                = FIND_HOST_URI + "smart/v1.0e1.0/key"
 
 # TALK
 TALK_HOST_URI               = "http://talk.smart-api.io/"
index 97416cf042447b6693ed758f2f8cc096f4fd6aee..a6fd8298f9ad78ab3ffa275ff07fbb8960467fa0 100644 (file)
@@ -25,12 +25,15 @@ class Activity(Evaluation):
                self.init_property(PROPERTY.HASOUTPUT, 'outputs', self.hasOutput, self.getOutputs, True)
                self.init_property(PROPERTY.HASREFOUTPUT, 'refOutputs', self.hasRefOutput, self.getRefOutputs, True)
                self.init_property(PROPERTY.HASAVAILABILITY, 'availabilities', self.hasAvailability, self.getAvailabilities, True)
+               self.init_property(PROPERTY.AUTHORIZATION, 'authorization', self.hasAuthorization, self.getAuthorization)
                self.init_property(PROPERTY.HASDATAAVAILABILITY, 'dataAvailabilities', self.hasDataAvailability, self.getDataAvailabilities, True)
                self.init_property(PROPERTY.INTERFACE, 'interfaces', self.hasInterface, self.getInterfaces, True)
                self.init_property(PROPERTY.ENTITY, 'entities', self.hasEntity, self.getEntities, True)
                
+               
        def _parseStatement(self, statement, custom_classes = None):
                from SmartAPI.model.Availability import Availability
+               from SmartAPI.model.Authorization import Authorization
                from SmartAPI.model.Input import Input
                from SmartAPI.model.Output import Output
                from SmartAPI.model.InterfaceAddress import InterfaceAddress
@@ -44,6 +47,7 @@ class Activity(Evaluation):
                self.parse_property(statement, PROPERTY.HASDATAAVAILABILITY, self.addDataAvailability, Availability, custom_classes = custom_classes)
                self.parse_property(statement, PROPERTY.INTERFACE, self.addInterface, InterfaceAddress, custom_classes = custom_classes)
                self.parse_property(statement, PROPERTY.ENTITY, self.addEntity, Entity, custom_classes = custom_classes)
+               self.parse_property(statement, PROPERTY.AUTHORIZATION, self.setAuthorization, Authorization, custom_classes = custom_classes)
                
                super(Activity, self)._parseStatement(statement, custom_classes = custom_classes)
 
@@ -89,6 +93,15 @@ class Activity(Evaluation):
        def addRefOutput(self, refOutput):
                self.refOutputs.append(refOutput)
 
+       def hasAuthorization(self):
+               return self.authorization is not None
+       
+       def getAuthorization(self):
+               return self.authorization
+       
+       def setAuthorization(self, authorization):
+               self.authorization = authorization
+       
        def hasAvailability(self):
                return len(self.availabilities) > 0
        
@@ -108,7 +121,7 @@ class Activity(Evaluation):
                self.dataAvailabilities.append(availability)
 
        def getInterfaces(self):
-               return self.interfaces;
+               return self.interfaces
        
        def hasInterface(self):
                return len(self.interfaces) > 0
diff --git a/Common/Python/SmartAPI/model/Authorization.py b/Common/Python/SmartAPI/model/Authorization.py
new file mode 100644 (file)
index 0000000..852135a
--- /dev/null
@@ -0,0 +1,44 @@
+from SmartAPI.common.PROPERTY import PROPERTY
+from SmartAPI.common.RESOURCE import RESOURCE
+from SmartAPI.model.Obj import Obj
+from SmartAPI.rdf.Variant import Variant
+
+
+class Authorization(Obj):
+
+       def __init__(self, uri = None):
+               Obj.__init__(self, uri)
+               self.setType(RESOURCE.AUTHORIZATION)
+               self.init_property(PROPERTY.PERSON, 'person', self.hasPerson, self.getPerson)
+               self.init_property(PROPERTY.METHOD, 'methods', self.hasMethod, self.getMethods, islist = True)
+               
+       def hasPerson(self):
+               return self.person is not None
+       
+       def getPerson(self):
+               return self.person
+
+       def setPerson(self, p):
+               if isinstance(p, str):
+                       _p = Person()
+                       _p.setUsername(p)
+               else:
+                       _p = p
+               self.person = _p
+
+       def hasMethod(self):
+               return len(self.methods) > 0
+       
+       def getMethods(self):
+               return self.methods
+
+       def addMethod(self, m):
+               if isinstance(m, str):
+                       m = Variant(m)
+               self.methods.append(m)
+               
+       def _parseStatement(self, statement, custom_classes = None):
+               self.parse_property(statement, PROPERTY.PERSON, self.setPerson, Person, custom_classes = custom_classes)
+               self.parse_property(statement, PROPERTY.METHOD, self.addMethod, Variant, custom_classes = custom_classes)
+               super(Authorization, self)._parseStatement(statement, custom_classes = custom_classes)
+       
index e1d691a776191f620253706780bd456a0448225b..a8fd8cf8ece614184739a2cf73e26652c7315039 100644 (file)
@@ -18,6 +18,7 @@ class Entity(Obj):
                self.init_property(PROPERTY.ZONE, 'zone', self.hasZone, self.getZone)
                self.init_property(PROPERTY.HASADDRESS, 'address', self.hasAddress, self.getAddress)
                self.init_property(PROPERTY.ISMANAGEDBY, 'managedBy', self.hasManagedBy, self.getManagedBy)
+               self.init_property(PROPERTY.ISSERVEDBY, 'servedBy', self.hasServedBy, self.getServedBy)
                self.init_property(PROPERTY.LOCATION, 'coordinates', self.hasCoordinates, self.getCoordinates)
                self.init_property(PROPERTY.ROUTE, 'route', self.hasRoute, self.getRoute)
                self.init_property(PROPERTY.DC_CREATOR, 'creators', self.hasCreator, self.getCreators, islist = True)
@@ -54,6 +55,7 @@ class Entity(Obj):
                self.parse_property(statement, PROPERTY.LOCATION, self.setCoordinates, Coordinates, custom_classes = custom_classes)
                self.parse_property(statement, PROPERTY.HASADDRESS, self.setAddress, Address, custom_classes = custom_classes)
                self.parse_property(statement, PROPERTY.ISMANAGEDBY, self.setManagedBy, Variant, custom_classes = custom_classes)
+               self.parse_property(statement, PROPERTY.ISSERVEDBY, self.setServedBy, Variant, custom_classes = custom_classes)
                self.parse_property(statement, PROPERTY.HASEVALUATION, self.addControllability, Controllability, custom_classes = custom_classes)
                self.parse_property(statement, PROPERTY.HASAVAILABILITY, self.addAvailability, Availability, custom_classes = custom_classes)
                self.parse_property(statement, PROPERTY.HASDATAAVAILABILITY, self.addDataAvailability, Availability, custom_classes = custom_classes)
@@ -200,6 +202,23 @@ class Entity(Obj):
        def getManagedBy(self):
                return self.managedBy
        
+       def hasServedBy(self):
+               return self.servedBy is not None
+       
+       def setServedBy(self, obj):
+               from SmartAPI.rdf.Variant import Variant
+               if isinstance(obj, Obj):
+                       self.servedBy = Variant(URIRef(obj.getIdentifierUri()))
+               elif isinstance(obj, str):
+                       self.servedBy = Variant(URIRef(obj))
+               elif isinstance(obj, URIRef):
+                       self.servedBy = Variant(obj)
+               else:
+                       self.servedBy = obj
+               
+       def getServedBy(self):
+               return self.servedBy
+       
        def hasInterface(self):
                return len(self.interfaces) > 0
                
index 4b8bad2f95de585ef3092db3262f9e1f15c1b0cc..ad58e37d595379b336aa0f7abb44277934d9e0a0 100644 (file)
@@ -702,7 +702,8 @@ class Obj(object):
 #              self.addType(RESOURCE.REFERENCE)
 #              self.addType(RESOURCE.ENCRYPTEDREFERENCE)
 
-               if isinstance(key, RSA._RSAobj):
+               # If not an instance of string (sym key), must be an instance of RSA (pub key)
+               if not isinstance(key, str):
 #                      self.setEncryptionKeyType(RESOURCE.PUBLICKEY)
                        return self.encryptWithPubKey(key)
 #                      
@@ -752,15 +753,15 @@ class Obj(object):
                Decrypt with SessionKey.
                
                Using encrypted string to recover the original Object.
-               @return a new Obj decrypted from cipertext, without those additional types like EncryptedReference and Reference, which
-               were inserted by encrypt() method before.    
-               '''             
+               @return a new Obj decrypted from cipertext, without additional types like EncryptedReference and Reference, which
+               were inserted by encrypt() method before.
+               '''
                
                if self.encryptedStringRepresentation is not None:
-                       if isinstance(key, RSA._RSAobj):
-                               decryptedString, symkey = SmartAPICrypto().asymmetricDecrypt(key, self.encryptedStringRepresentation)
-                       else:
+                       if isinstance(key, str):
                                decryptedString = SmartAPICrypto().symmetricDecrypt(key, self.encryptedStringRepresentation)
+                       else:
+                               decryptedString, symkey = SmartAPICrypto().asymmetricDecrypt(key, self.encryptedStringRepresentation)
                        
                        model = Tools().fromString(decryptedString, serialization)
                        # find the resource which was encrypted
diff --git a/Examples/Python/AdaptDataService/AdaptDataService.py b/Examples/Python/AdaptDataService/AdaptDataService.py
new file mode 100755 (executable)
index 0000000..e7d51fa
--- /dev/null
@@ -0,0 +1,218 @@
+#!/usr/bin/python
+
+from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+from io import BytesIO
+import traceback
+
+from SmartAPI.agents.RegistrationAgent import RegistrationAgent
+from SmartAPI.agents.SearchAgent import SearchAgent
+
+from SmartAPI.common.Tools import Tools
+from SmartAPI.common.RESOURCE import RESOURCE
+
+from SmartAPI.factory.ResponseFactory import ResponseFactory
+
+from SmartAPI.model.Activity import Activity
+from SmartAPI.model.Authorization import Authorization
+from SmartAPI.model.Entity import Entity
+from SmartAPI.model.InterfaceAddress import InterfaceAddress
+from SmartAPI.model.Organization import Organization
+from SmartAPI.model.Service import Service
+from SmartAPI.model.TimeSeries import TimeSeries
+from SmartAPI.model.ValueObject import ValueObject
+
+
+myIdentity = "http://adapt.asema.com/demos/python/datasource/"
+adaptServiceIdentity = "http://adapt.asema.com"
+registrationServerUri = "http://find.smart-api.io/smart/v1.0e1.0/access"
+
+PORT = 8111
+
+
+
+class SampleRegistration(object):
+       
+
+       def __init__(self):
+               pass
+
+       def run(self):
+               agent = RegistrationAgent(myIdentity)
+               agent.setServerAddress(registrationServerUri)
+               agent.setDebugMode(True)
+
+               # registrate
+               try:
+                       org = Organization()
+                       org.setName("Asema Electronics Ltd")
+                       
+                       sampleService = Service(myIdentity)
+                       sampleService.setName("Asema Adapt demo data service")
+                       sampleService.setDescription("Demo code for a data source that is compatible with Adapt")
+                       sampleService.setCoordinates(latitude=60.180824, longitude=24.832116)
+                       sampleService.setOwner(org)
+       
+                       auth = Authorization()
+                       auth.addMethod(RESOURCE.COOKIE);
+                       auth.addMethod(RESOURCE.HTTPSTANDARD);
+       
+                       iface = InterfaceAddress()
+                       iface.setHost("adapt.asema.com")
+                       iface.setPath("/test/")
+                       iface.setPort(80)
+                       iface.setScheme("http")
+
+                       read = Activity()
+                       read.setMethod(RESOURCE.READ)
+                       read.setInterface(iface)
+                       read.setAuthorization(auth)
+
+                       dataSource = Entity()
+                       dataSource.setIdentifierUri(myIdentity + "devices/Cdemodevice")
+                       dataSource.setName("Demo Adapt datasource")
+                       dataSource.addCapability(read)
+                       dataSource.setManagedBy(myIdentity)
+                       dataSource.setServedBy(adaptServiceIdentity)
+                       dataSource.setCoordinates(latitude=60.180824, longitude=24.832116)
+
+                       dataSource.addCapability(read)
+                       
+                       power = ValueObject(myIdentity + "service/Ppower")
+                       power.addType(RESOURCE.READABLE)
+                       power.setQuantity(RESOURCE.POWER)
+                       power.setUnit(RESOURCE.AMPERE)
+                       power.setMaximum(1000.0)
+                       power.setMinimum(0.0)
+
+                       dataSource.addValueObject(power)
+
+                       agent.addEntity(sampleService)
+                       agent.addEntity(dataSource);
+
+                       r = agent.registrate()
+                       if r is None or r.hasErrors():
+                               print "Demo data service registration FAILED"
+                               return False
+                       return True
+               
+               except:
+                       print "Error in registration code:"
+                       traceback.print_exc()
+                       return False
+
+
+class SampleDataService(BaseHTTPRequestHandler):
+       
+       def __init__(self, request, client_address, server):
+               BaseHTTPRequestHandler.__init__(self, request, client_address, server)
+               
+       # HANDLE GET REQUESTS
+       def do_GET(self):
+               self.send_response(200)
+               self.end_headers()
+                       
+               print("GET " + self.path)
+                       
+               req_path = self.path.rstrip('/')
+                       
+               if req_path.endswith("/identify"):
+                       self.wfile.write(str.encode(myIdentity))
+               elif req_path.endswith("/authorize"):
+                       response_activity = Activity()
+                       response = response_activity.toString()
+                       print("GET " + response)
+                       self.wfile.write(str.encode(response))
+               else:
+                       print("unhandled request received!")
+       
+       # HANDLE POST REQUESTS
+       def do_POST(self):
+               content_length = int(self.headers['Content-Length'])
+               body = self.rfile.read(content_length)
+               self.send_response(200)
+               self.end_headers()
+               response_bytes = BytesIO()
+               
+               print("POST" + self.path)
+               print("POST DATA: " + body)
+               
+               req_path = self.path.rstrip('/')
+               
+               if req_path.endswith("/authorize"):
+                       # Reply with empty activity to authorize
+                       response_activity = Activity()
+                       response_text = response_activity.toString()
+                       print("POST AUTHORIZE" + response_text)
+                       response_bytes.write(response_text)
+                       
+               elif req_path.endswith("/access"):
+                       request = Tools.parseRequest(body)
+                       print("request: " + request.toString())
+                               
+                       activity = request.getActivities()[0]  # type: Activity
+                               
+                       # Handle timeseries request
+                       if activity.hasTemporalContext():
+                               response_bytes.write(self.handleTemporalContext(activity, request))
+                       else:
+                               print("unhandled request received!")
+               
+               else:
+                       print("unhandled request received!")
+               
+               # Write output to client
+               self.wfile.write(response_bytes.getvalue())
+       
+       
+       def handleTemporalContext(self, activity, request):
+               print("Timeseries request: ")
+               print("start")
+               print(activity.temporalContext.start)
+               print("end")
+               print(activity.temporalContext.end)
+               
+               # For the client to recognize from which activity this result is, the response
+               # activity will carry the same identifier that was in the request
+               response = ResponseFactory.create(myIdentity, request)
+               response_activity = Activity(activity.getIdentifierUri())
+               
+               """
+               The way results are obtained is up to the server. This could
+               for instance be a result from a database query,
+               """
+               results = [
+                       {'time': '2019-06-10T15:18:54.842', 'power': 25},
+                       {'time': '2019-06-01T02:11:54.842', 'power': 21},
+                       {'time': '2019-05-25T11:11:54.842', 'power': 32}]
+               
+               time_series = TimeSeries()
+               
+               # Add data to response timeseries
+               for r in results:
+                       value_object = ValueObject()
+                       value_object.setInstant(r["time"])
+                       value_object.setValue(r["power"])
+                       
+                       time_series.addListItem(value_object)
+                       
+                       # Add timeseries to respose activity
+                       response_activity.addTimeSerie(time_series)
+                       
+                       response.addActivity(response_activity)
+                       
+                       print("Reply:")
+                       print(Tools.serializeResponse(response)[0])
+                       return Tools.serializeResponse(response)[0]
+
+
+def main():
+       registrator = SampleRegistration()
+       registrator.run()
+       
+       httpd = HTTPServer(('', PORT), SampleDataService)
+       httpd.serve_forever()
+
+
+if __name__ == '__main__':
+       main()
+