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