Add sample search for Adapt registration
[smartapi.git] / Common / Python / SmartAPI / agents / SearchAgent.py
1 #!/usr/bin/python
2
3 """ 
4 """
5
6 import sys
7 import json
8 import urllib, urllib2
9 import datetime
10 from pytz import timezone
11 from urlparse import urlparse
12 from SmartAPI.agents.Agent import Agent
13 from SmartAPI.model.Entity import Entity
14 from SmartAPI.model.Activity import Activity
15 from SmartAPI.model.Coordinates import Coordinates
16 from SmartAPI.model.Ring import Ring
17 from SmartAPI.model.ValueObject import ValueObject
18 from SmartAPI.rdf.Variant import Variant
19 from SmartAPI.common.HttpClient import HttpClient
20 from SmartAPI.common.RESOURCE import RESOURCE
21 from SmartAPI.common.PROPERTY import PROPERTY
22 from SmartAPI.common.Tools import Tools
23 from SmartAPI.common.NS import NS
24 from SmartAPI.model.Condition import Condition
25 from SmartAPI.model.Obj import Obj
26 from isodate.duration import Duration
27 from SmartAPI.common.URLs import *
28 from SmartAPI.common.ACTIVITIES import *
29
30 import traceback
31 from rdflib.term import URIRef
32
33
34 class SearchAgent(Agent):
35     remoteURL = FIND_URI
36     debug = False
37     
38     def __init__(self, myUri=''):
39         Agent.__init__(self)
40         self.generatedBy = myUri
41         self.entity = Entity()
42         #self.entity.clearTypes()
43         self.httpClient = HttpClient()
44         self.serialization = 'text/turtle'
45         
46     @classmethod
47     def setRegistrationServiceUri(cls, serverURI):
48         cls.setServerAddress(serverURI)
49     
50     def setEntity(self, e):
51         self.entity = e
52     
53     def doSearch(self):
54         return self.search()
55     
56     def search(self):
57         from SmartAPI.model.Response import Response
58         
59         # serialize data
60         messageBody = self._generateSearchMessage()
61         if SearchAgent.debug:
62             print '\n Request to SMARTAPI Search Service:'
63             print messageBody, '\n'
64         
65         try:
66             # send message
67             responseStr = self.httpClient.sendPost(self.serverAddress, messageBody, self.serialization, self.serialization, seasMethod=self.httpClient.SMARTAPI_METHOD_REQUEST)[0]                        
68             response = Response.fromString(responseStr, self.serialization)
69             if response is not None:
70                 if SearchAgent.debug:
71                     print '\n Response from SMARTAPI Search Service:'
72                     print Tools.toString(response, self.serialization)
73                     Tools.printErrors(response)
74                 if (response.hasActivity()):
75                     return response.firstActivity().getEntities()
76                 else:
77                     print 'ERROR: SearchAgent: the received response has no Activity'
78                     return None
79             
80             else:
81                 if SearchAgent.debug:
82                     print '\n Response from SMARTAPI Search Service:'
83                     print responseStr, '\n'
84                 return None
85         except:
86             print 'Exception while sending an HTTP request to ', self.serverAddress
87             traceback.print_exc()
88     
89     @classmethod
90     def searchByNameAndType(cls, myId, freshnessInDays, keywords, types):
91         '''
92         @type keywords, types: list of Strings
93         @type freshnessInDays: integer
94         @type myId: String
95         '''
96         agent = SearchAgent(myId)
97         agent.anyOfTypes(types)
98         agent.daysOldData(freshnessInDays)
99         agent.anyOfNames(keywords)
100         return agent.search()
101     
102     @classmethod
103     def searchByName(cls, myId, keyword):
104         agent = SearchAgent(myId)
105         agent.ofName(keyword)
106         return agent.search()
107     
108     @classmethod
109     def searchByType(cls, myId, type):
110         agent = SearchAgent(myId)
111         agent.ofType(type)
112         return agent.search()
113             
114     @classmethod
115     def searchByDescription(cls,  myId, freshnessInDays, searchString, types = [RESOURCE.ENTITY]):
116         agent = SearchAgent(myId)
117         agent.anyOfTypes(types)
118         agent.daysOldData(freshnessInDays)
119         agent.ofDescription(searchString)
120         return agent.search()
121     
122     @classmethod
123     def searchById(cls, myId, searchString, entityType=None, freshnessInDays=None):
124         '''
125         This is new version
126         @param searchString: Entity partial url 
127         @param entityType: SmartAPI resource URL. If exist, it can narrow down searching result to specified
128         Entity subtype.
129         '''
130         agent = SearchAgent(myId)
131         if entityType is not None:
132             agent.ofType(entityType)
133         else:
134             agent.ofType(RESOURCE.ENTITY);
135         agent.ofId(searchString)
136         
137         if freshnessInDays is not None:
138             agent.daysOldData(freshnessInDays)
139             
140         return agent.search()
141     
142     @classmethod
143     def searchByRegistrant(cls, myId, registrantId, entityType=None):
144         '''
145         This is new version.
146         @param registrantId: registor URI
147         @param entityType: SmartAPI resource URL. If exist, it can narrow down searching result to specified
148         Entity subtype.
149         '''
150         agent = SearchAgent(myId)
151         agent.ofRegistrant(registrantId)
152         if entityType is not None:
153             agent.ofType(entityType)
154             
155         return agent.search()
156     
157     @classmethod
158     def fetchBySmartAPIId(cls, myId, idToFetch):
159         '''
160         only return one entity if there is.
161         '''  
162         agent = SearchAgent(myId)
163         e = Entity(idToFetch)
164         #e.clearTypes()
165         agent.entity = e
166         res = agent.search()
167         if res is not None and len(res) > 0:
168             return res[0]
169         
170     @classmethod
171     def searchByPoint(cls, myId, latitude, longitude, distanceInKm, entityType=None):
172         '''
173         This is new version.
174         ''' 
175         agent = SearchAgent(myId)
176         coords = Coordinates(latitude=latitude, longitude=longitude)
177         agent.pointSearchArea(coords, distanceInKm)
178         
179         if entityType is not None:
180             agent.ofType(entityType)
181             
182         return agent.search()
183     
184     @classmethod
185     def searchByPointAndType(cls, myId, freshnessInDays, latitude, longitude, distanceInKm, type):
186         agent = SearchAgent(myId)
187         agent.ofType(type)
188         agent.daysOldData(freshnessInDays)
189         
190         coords = Coordinates(latitude=latitude, longitude=longitude)
191         agent.pointSearchArea(coords, distanceInKm)
192         return agent.search()
193     
194     def rectangleSearchArea(self, minCoords, maxCoords):
195         '''
196         Define bounding box search area
197         @param minCoordinates: Coordinate type
198         @param maxCoordinates: Coordinate type
199         '''
200         self.entity.add(URIRef(PROPERTY.MINLOCATION), minCoords)
201         self.entity.add(URIRef(PROPERTY.MAXLOCATION), maxCoords)
202     
203     def ringSearchArea(self, center, minRadius, maxRadius):
204         '''
205         Define ring shape search area
206         @type center: Coordinate 
207         @type minRadius: double
208         @type maxRadius: double
209         '''
210         from SmartAPI.model.Ring import Ring
211     
212         ring = Ring()
213         ring.add(URIRef(PROPERTY.LAT), center.getLatitude())
214         ring.add(URIRef(PROPERTY.LONG), center.getLongitude())
215         
216         minR = ValueObject()
217         minR.setQuantity(RESOURCE.LENGTH)
218         minR.setUnit(RESOURCE.KILOMETER)
219         minR.setValue(Variant(minRadius))
220         ring.setMinRadius(minR)
221         maxR = ValueObject()
222         maxR.setQuantity(RESOURCE.LENGTH)
223         maxR.setUnit(RESOURCE.KILOMETER)
224         maxR.setValue(Variant(maxRadius))
225         ring.setMaxRadius(maxR)
226         self.entity.add(NS.SMARTAPI + "ring", ring)
227     
228     def polygonSearchArea(self, polygon):
229         self.entity.add(URIRef(RESOURCE.POLYGON), polygon)
230     
231     def pointSearchArea(self, center, kilometers):
232         '''
233         define circular search area
234         @type center: Coordinate
235         @type kilometers: double 
236         '''
237         ring = Ring()
238         ring.setCoordinates(center)
239         
240         maxR = ValueObject()
241         maxR.setQuantity(RESOURCE.LENGTH)
242         maxR.setUnit(RESOURCE.KILOMETER)
243         maxR.setValue(Variant(kilometers))
244         ring.setMaxRadius(maxR)
245         self.entity.add(URIRef(NS.SMARTAPI + "ring"), ring)
246     
247     def ofId(self, searchString):
248         condition = Condition()
249         condition.addRegex("(?i)" + searchString)
250         self.entity.add(URIRef(PROPERTY.ID), condition)
251         
252     def ofDescription(self, searchString):
253         condition = Condition()
254         condition.addRegex("(?i)" + searchString)
255         self.entity.add(URIRef(PROPERTY.COMMENT), condition)
256        
257     def ofType(self, type):
258         '''
259         define type to search
260         '''
261         if isinstance(type, str):
262             type = URIRef(type)
263         self.entity.addType(type)
264         
265     def ofRegistrant(self, id):
266         self.entity.add(URIRef(PROPERTY.ISREGISTEREDBY), URIRef(id))
267         
268     def anyOfTypes(self, types):
269         '''
270         Define all the types that can match
271         '''
272         if len(types) == 1:
273             self.ofType(types[0])
274         elif len(types) > 1:
275             condition = Condition()
276             for type in types:
277                 condition.addOr(Obj(type))
278             self.entity.clearTypes()
279             self.entity.addType(condition)
280     
281     def daysOldData(self, days):
282         '''
283         Define how many days old data will be searched.
284         '''
285         duration = Duration(days=days)
286         self.entity.add(URIRef(PROPERTY.FRESHNESS), duration)
287     
288     def monthsOldData(self, months):
289         '''
290         Define how many months old data will be searched.
291         '''
292         duration = Duration(months=months)
293         self.entity.add(URIRef(PROPERTY.FRESHNESS), duration)
294     
295     def yearsOldData(self, years):
296         '''
297         Define how many years old data will be searched.
298         '''
299         duration = Duration(years=years)
300         self.entity.add(URIRef(PROPERTY.FRESHNESS), duration)
301     
302     def hoursOldData(self, hours):
303         duration = Duration(hours=hours)
304         self.entity.add(URIRef(PROPERTY.FRESHNESS), duration)
305     
306     def minutesOldData(self, minutes):
307         duration = Duration(minutes=minutes)
308         self.entity.add(URIRef(PROPERTY.FRESHNESS), duration) 
309     
310     def anyOfNames(self, searchStrings):
311         '''
312         Define multiple search strings for the entity name (label). Will return also partial hits 
313         for any of the strings.
314         '''
315         if len(searchStrings) > 0:
316             condition = Condition()
317             for stri in searchStrings:
318                 condition.addRegex("(?i)" + stri)
319             
320             self.entity.add(URIRef(PROPERTY.RDFS_LABEL), condition);
321          
322     def ofName(self, searchString, exactMatch=False):
323         '''
324         Define search string for the name (rdfs:label) of the entity
325           @param searchString search string
326           @param exactMatch true if string has to match completely, false for partial hits
327         '''
328         if exactMatch:
329             self.entity.setName(searchString)
330         else:
331             condition = Condition()
332             condition.addRegex("(?i)" + searchString)
333             self.entity.add(URIRef(PROPERTY.RDFS_LABEL), condition)
334     
335     def ofOutputCategory(self, category):
336         from SmartAPI.model.Activity import Activity
337         from SmartAPI.model.Output import Output
338         '''
339         Define output category to search
340         @param category string
341         '''
342         activity = Activity()
343         self.entity.addCapability(activity)
344         output = Output()
345         activity.addOutput(output)
346         output.setCategory(category)
347     
348     @classmethod
349     def setDebugMode(cls, debuging):
350         cls.debug = debuging
351         
352     def _generateSearchMessage(self):
353         from SmartAPI.factory.RequestFactory import RequestFactory
354     
355         request = RequestFactory().create(self.generatedBy)
356         
357         activity = Activity(SEARCH)
358         activity.setMethod(RESOURCE.READ)
359         activity.addEntity(self.entity)
360         request.addActivity(activity)
361         
362         return Tools.toString(request, self.serialization)
363
364