00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 import roslib.message
00037 import rospy
00038 import unique_id
00039
00040 import warehouse_ros as wr
00041
00042 from map_manager import *
00043 from yaml_database import *
00044
00045 from world_canvas_msgs.msg import *
00046 from world_canvas_msgs.srv import *
00047 from world_canvas_utils.serialization import *
00048
00049
00050 class AnnotationsServer:
00051
00052
00053
00054
00055
00056 def __init__(self):
00057
00058
00059
00060 self.world_collection = \
00061 wr.MessageCollection("world_canvas", "worlds", WorldCanvas)
00062 self.world_collection.ensure_index("id", unique=True)
00063
00064 self.anns_collection = \
00065 wr.MessageCollection("world_canvas", "annotations", Annotation)
00066 self.anns_collection.ensure_index("id", unique=True)
00067
00068 self.data_collection = \
00069 wr.MessageCollection("world_canvas", "annotations_data", AnnotationData)
00070 self.data_collection.ensure_index("id", unique=True)
00071
00072
00073 self.get_anns_srv = \
00074 rospy.Service('get_annotations', GetAnnotations, self.get_annotations)
00075 self.get_data_srv = \
00076 rospy.Service('get_annotations_data', GetAnnotationsData, self.get_annotations_data)
00077 self.pub_data_srv = \
00078 rospy.Service('pub_annotations_data', PubAnnotationsData, self.pub_annotations_data)
00079
00080 self.del_anns_srv = \
00081 rospy.Service('delete_annotations', DeleteAnnotations, self.delete_annotations)
00082 self.save_data_srv = \
00083 rospy.Service('save_annotations_data', SaveAnnotationsData, self.save_annotations_data)
00084
00085 self.list_worlds_srv = \
00086 rospy.Service('list_worlds', ListWorlds, self.list_worlds)
00087
00088 self.set_keyword_srv = \
00089 rospy.Service('set_keyword', SetKeyword, self.set_keyword)
00090 self.set_related_srv = \
00091 rospy.Service('set_relationship', SetRelationship, self.set_relationship)
00092
00093 self.reset_database_srv = \
00094 rospy.Service('reset_database', ResetDatabase, self.reset_database)
00095
00096
00097 self.yaml_db = YAMLDatabase(self.anns_collection, self.data_collection)
00098
00099
00100 if rospy.get_param('~start_map_manager', False):
00101 self.map_mng = MapManager()
00102
00103 rospy.loginfo("Annotations server : initialized.")
00104
00105
00106
00107
00108
00109
00110 def get_annotations(self, request):
00111
00112 response = GetAnnotationsResponse()
00113
00114
00115
00116
00117 query = {'$and':[]}
00118 query['$and'].append({'world': {'$in': [request.world]}})
00119 if len(request.ids) > 0:
00120 query['$and'].append({'id': {'$in': [unique_id.toHexString(id) for id in request.ids]}})
00121 if len(request.names) > 0:
00122 query['$and'].append({'name': {'$in': request.names}})
00123 if len(request.types) > 0:
00124 query['$and'].append({'type': {'$in': request.types}})
00125 if len(request.keywords) > 0:
00126 query['$and'].append({'keywords': {'$in': request.keywords}})
00127 if len(request.relationships) > 0:
00128 query['$and'].append({'relationships': {'$in': [unique_id.toHexString(r) for r in request.relationships]}})
00129
00130
00131 rospy.logdebug("Find annotations with query %s" % query)
00132 matching_anns = self.anns_collection.query(query)
00133
00134 i = 0
00135 while True:
00136 try:
00137 response.annotations.append(matching_anns.next()[0])
00138 i += 1
00139 except StopIteration:
00140 if (i == 0):
00141 rospy.loginfo("No annotations found")
00142 return self.service_success(response)
00143 break
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 rospy.loginfo("%lu annotations loaded" % i)
00159 return self.service_success(response)
00160
00161 def get_annotations_data(self, request):
00162 response = GetAnnotationsDataResponse()
00163
00164 if len(request.annotation_ids) == 0:
00165 return self.service_error(response, "No annotation ids on request; you must be kidding!")
00166
00167 query = {'id': {'$in': [unique_id.toHexString(id) for id in request.annotation_ids]}}
00168 matching_data = self.data_collection.query(query)
00169 rospy.logdebug("Load annotations data with query %s" % query)
00170
00171 i = 0
00172 while True:
00173 try:
00174 response.data.append(matching_data.next()[0])
00175 i += 1
00176 except StopIteration:
00177 if (i == 0):
00178
00179 rospy.loginfo("No data found for %d requested annotations" % len(request.annotation_ids))
00180 else:
00181 rospy.loginfo("%d objects found for %d annotations" % (i, len(request.annotation_ids)))
00182 break
00183
00184 return self.service_success(response)
00185
00186 def pub_annotations_data(self, request):
00187 response = PubAnnotationsDataResponse()
00188
00189 if len(request.annotation_ids) == 0:
00190 return self.service_error(response, "No annotation ids on request; you must be kidding!")
00191
00192
00193
00194 query = {'data_id': {'$in': [unique_id.toHexString(id) for id in request.annotation_ids]}}
00195 matching_anns = self.anns_collection.query(query, metadata_only=True)
00196 while True:
00197 try:
00198
00199 ann_md = matching_anns.next()
00200 if 'topic_type' not in locals():
00201 topic_type = ann_md['type']
00202 elif topic_type != ann_md['type']:
00203 return self.service_error(response, "Cannot publish annotations of different types (%s, %s)"
00204 % (topic_type, ann_md['type']))
00205 except StopIteration:
00206 break
00207
00208 if 'topic_type' not in locals():
00209 return self.service_error(response, "None of the %d requested annotations was found in database"
00210 % len(request.annotation_ids))
00211
00212
00213 msg_class = roslib.message.get_message_class(topic_type)
00214 if msg_class is None:
00215
00216
00217
00218 return self.service_error(response, "Topic type %s definition not found" % topic_type)
00219
00220
00221
00222 if request.pub_as_list:
00223 topic_type = request.topic_type
00224 topic_class = roslib.message.get_message_class(topic_type)
00225 if topic_class is None:
00226
00227 return self.service_error(response, "Topic type %s definition not found" % topic_type)
00228 else:
00229 topic_class = msg_class
00230
00231 pub = rospy.Publisher(request.topic_name, topic_class, latch=True, queue_size=5)
00232
00233
00234 query['id'] = query.pop('data_id')
00235 matching_data = self.data_collection.query(query)
00236 rospy.logdebug("Publish data for annotations on query %s" % query)
00237
00238 i = 0
00239 object_list = list()
00240 while True:
00241 try:
00242
00243 ann_data = matching_data.next()[0]
00244 ann_msg = deserialize_msg(ann_data.data, msg_class)
00245 if request.pub_as_list:
00246 object_list.append(ann_msg)
00247 else:
00248 pub.publish(ann_msg)
00249
00250 i += 1
00251 except SerializationError as e:
00252 rospy.logerr("Deserialization failed: %s" % str(e))
00253 continue
00254 except StopIteration:
00255 if (i == 0):
00256
00257 return self.service_error(response, "No data found for %d requested annotations"
00258 % len(request.annotation_ids))
00259 if i != len(request.annotation_ids):
00260
00261 rospy.logwarn("Only %d objects found for %d annotations" % (i, len(request.annotation_ids)))
00262 else:
00263 rospy.loginfo("%d objects found for %d annotations" % (i, len(request.annotation_ids)))
00264 if request.pub_as_list:
00265 pub.publish(object_list)
00266 break
00267
00268 return self.service_success(response)
00269
00270 def delete_annotations(self, request):
00271 '''
00272 Deletes the given annotations and its data from database.
00273
00274 @param request: Service request.
00275 '''
00276 response = DeleteAnnotationsResponse()
00277
00278 if len(request.annotations) == 0:
00279 return self.service_error(response, "No annotation ids on request; you must be kidding!")
00280
00281 annot_data_ids = [a.data_id for a in request.annotations]
00282 query = {'id': {'$in': [unique_id.toHexString(id) for id in annot_data_ids]}}
00283 rospy.logdebug("Removing %d annotations data with query %s" % (len(annot_data_ids), query))
00284 data_removed = self.data_collection.remove(query)
00285
00286 annotation_ids = [a.id for a in request.annotations]
00287 query = {'id': {'$in': [unique_id.toHexString(id) for id in annotation_ids]}}
00288 rospy.logdebug("Removing %d annotations with query %s" % (len(annotation_ids), query))
00289 removed = self.anns_collection.remove(query)
00290 rospy.loginfo("%d annotations and %d data removed from database" % (removed, data_removed))
00291
00292 if removed != len(annotation_ids):
00293
00294
00295
00296 rospy.logwarn("Requested (%d) and deleted (%d) annotations counts doesn't match"
00297 % (len(annotation_ids), removed))
00298
00299 return self.service_success(response)
00300
00301 def save_annotations_data(self, request):
00302 '''
00303 Legacy method kept for debug purposes: saves together annotations and its data
00304 assuming a 1-1 relationship.
00305
00306 @param request: Service request.
00307 '''
00308 response = SaveAnnotationsDataResponse()
00309
00310 print request.annotations
00311 for annotation, data in zip(request.annotations, request.data):
00312
00313
00314 metadata = { 'world' : annotation.world,
00315 'data_id' : unique_id.toHexString(annotation.data_id),
00316 'id' : unique_id.toHexString(annotation.id),
00317 'name' : annotation.name,
00318 'type' : annotation.type
00319 }
00320
00321
00322 if len(annotation.keywords) > 0:
00323 metadata['keywords'] = annotation.keywords
00324 if len(annotation.relationships) > 0:
00325 metadata['relationships'] = [unique_id.toHexString(r) for r in annotation.relationships]
00326
00327
00328 data_metadata = { 'id' : unique_id.toHexString(annotation.data_id) }
00329
00330 rospy.logdebug("Saving annotation %s for world %s" % (annotation.id, annotation.world))
00331
00332
00333 self.anns_collection.remove({'id': {'$in': [unique_id.toHexString(annotation.id)]}})
00334 self.anns_collection.insert(annotation, metadata)
00335 self.data_collection.remove({'id': {'$in': [unique_id.toHexString(annotation.data_id)]}})
00336 self.data_collection.insert(data, data_metadata)
00337
00338 rospy.loginfo("%lu annotations saved" % len(request.annotations))
00339 return self.service_success(response)
00340
00341 def list_worlds(self, request):
00342 response = ListWorldsResponse()
00343
00344
00345
00346 anns_metadata = self.anns_collection.query({}, metadata_only=True, sort_by='world')
00347 while True:
00348 try:
00349 metadata = anns_metadata.next()
00350 if response.names[-1] != metadata['world']:
00351 response.names.append(metadata['world'])
00352 except IndexError:
00353 response.names.append(metadata['world'])
00354 except StopIteration:
00355 return response
00356
00357 def set_keyword(self, request):
00358 response = SetKeywordResponse()
00359 annot_id, metadata = self.get_metadata(request.id)
00360
00361 if metadata is None:
00362 response.message = "Annotation not found"
00363 response.result = False
00364 return response
00365
00366 if request.action == SetKeywordRequest.ADD:
00367 return self.add_element(annot_id, request.keyword, metadata, 'keywords', response)
00368 elif request.action == SetKeywordRequest.DEL:
00369 return self.del_element(annot_id, request.keyword, metadata, 'keywords', response)
00370 else:
00371
00372 rospy.logerr("Invalid action %d", request.action)
00373 response.message = "Invalid action: %d" % request.action
00374 response.result = False
00375 return response
00376
00377
00378 def set_relationship(self, request):
00379 response = SetRelationshipResponse()
00380 annot_id, metadata = self.get_metadata(request.id)
00381 relat_id = unique_id.toHexString(request.relationship)
00382
00383 if metadata is None:
00384 response.message = 'Annotation not found'
00385 response.result = False
00386 return response
00387
00388 if request.action == SetRelationshipRequest.ADD:
00389 return self.add_element(annot_id, relat_id, metadata, 'relationships', response)
00390 elif request.action == SetRelationshipRequest.DEL:
00391 return self.del_element(annot_id, relat_id, metadata, 'relationships', response)
00392 else:
00393
00394 rospy.logerr("Invalid action: %d" % request.action)
00395 response.message = "Invalid action: %d" % request.action
00396 response.result = False
00397 return response
00398
00399
00400 def add_element(self, annot_id, element, metadata, md_field, response):
00401
00402
00403 field = metadata.get(md_field)
00404
00405
00406 if field is None:
00407 field = []
00408 if element not in field:
00409 field.append(element)
00410 metadata[md_field] = field
00411 self.anns_collection.update(metadata)
00412 rospy.loginfo("%s added to %s for annotation %s" % (element, md_field, annot_id))
00413 else:
00414
00415 rospy.loginfo("%s already set on %s for annotation %s" % (element, md_field, annot_id))
00416
00417 return self.service_success(response)
00418
00419 def del_element(self, annot_id, element, metadata, md_field, response):
00420
00421 field = metadata.get(md_field)
00422
00423
00424 if field is None or element not in field:
00425
00426 rospy.logerr("%s not found on %s for annotation %s" % (element, md_field, annot_id))
00427 response.message = element + ' not found'
00428 response.result = False
00429 return response
00430 else:
00431
00432 rospy.loginfo("%s deleted on %s for annotation %s" % (element, md_field, annot_id))
00433 field.remove(element)
00434 if len(field) == 0:
00435 del metadata[md_field]
00436 else:
00437 metadata[md_field] = field
00438 self.anns_collection.update(metadata)
00439
00440
00441 return self.service_success(response)
00442
00443 def reset_database(self, request):
00444
00445 self.world_collection.remove({})
00446 self.anns_collection.remove({})
00447 self.data_collection.remove({})
00448
00449
00450 return self.service_success(ResetDatabaseResponse(), 'Database cleared!')
00451
00452
00453
00454
00455
00456
00457 def get_metadata(self, uuid):
00458
00459 annot_id = unique_id.toHexString(uuid)
00460 matching_anns = self.anns_collection.query({'id': {'$in': [annot_id]}}, True)
00461
00462 try:
00463 return annot_id, matching_anns.next()
00464 except StopIteration:
00465 rospy.logwarn("Annotation %s not found" % annot_id)
00466 return annot_id, None
00467
00468 def service_success(self, response, message=None):
00469 if message is not None:
00470 rospy.loginfo(message)
00471 response.result = True
00472 return response
00473
00474 def service_error(self, response, message):
00475 rospy.logerr(message)
00476 response.message = message
00477 response.result = False
00478 return response