def _get_data(relative_url): """ Helper method accesses a URL on the server and returns the data (interprets the JSON). @param relative_url: The relative URL on the server. A starting slash may be specified, but either way, it's always interpreted to be relative to "/". @type relative_url: string @return: The JSON interpreted data and the response object as a tuple. @rtype tuple """ if DOCROOT: if relative_url.startswith(DOCROOT): relative_url = relative_url[len(DOCROOT):] if relative_url.startswith("/"): relative_url = relative_url[1:] resp = http.urlopen("GET", SERVER_URL + "/" + relative_url, headers={"Accept" : "application/json"}) buf = resp.read() if resp.getStatus() == 200: data = json.loads(buf) else: data = buf return (data, resp)
def _send_data(relative_url, obj): """ Helper method that POSTs an object to URL as JSON. @param relative_url: The relative URL on the server. A starting slash may be specified, but either way, it's always interpreted to be relative to "/". @type relative_url: string @param obj: The object to be parsed to JSON and sent. @type obj: object @return: The JSON interpreted data and the response object as a tuple. @rtype tuple """ if DOCROOT: if relative_url.startswith(DOCROOT): relative_url = relative_url[len(DOCROOT):] if relative_url.startswith("/"): relative_url = relative_url[1:] resp = http.urlopen("POST", SERVER_URL + "/" + relative_url, headers={"Accept" : "application/json"}, data=json.dumps(obj)) buf = resp.read() if resp.getStatus() >= 200 and resp.getStatus() <= 300: data = json.loads(buf) else: data = buf return (data, resp)
def _get_data(relative_url): """ Helper method accesses a URL on the server and returns the data (interprets the JSON). @param relative_url: The relative URL on the server. A starting slash may be specified, but either way, it's always interpreted to be relative to "/". @type relative_url: string @return: The JSON interpreted data and the response object as a tuple. @rtype tuple """ if DOCROOT: if relative_url.startswith(DOCROOT): relative_url = relative_url[len(DOCROOT):] if relative_url.startswith("/"): relative_url = relative_url[1:] resp = http.urlopen("GET", SERVER_URL + "/" + relative_url, headers={"Accept": "application/json"}) buf = resp.read() if resp.getStatus() == 200: data = json.loads(buf) else: data = buf return (data, resp)
def _send_data(relative_url, obj): """ Helper method that POSTs an object to URL as JSON. @param relative_url: The relative URL on the server. A starting slash may be specified, but either way, it's always interpreted to be relative to "/". @type relative_url: string @param obj: The object to be parsed to JSON and sent. @type obj: object @return: The JSON interpreted data and the response object as a tuple. @rtype tuple """ if DOCROOT: if relative_url.startswith(DOCROOT): relative_url = relative_url[len(DOCROOT):] if relative_url.startswith("/"): relative_url = relative_url[1:] resp = http.urlopen("POST", SERVER_URL + "/" + relative_url, headers={"Accept": "application/json"}, data=json.dumps(obj)) buf = resp.read() if resp.getStatus() >= 200 and resp.getStatus() <= 300: data = json.loads(buf) else: data = buf return (data, resp)
def parse(self, data): """ Take input in this renderer's format and produce an object. @param data: An input containing the serialized representation of an object in this renderer's format. @param data: string @return: Object that was de-serialized from this input. @rtype: object """ obj = json.loads(data) return obj['undefined']
def loadResourceFromStorage(self, resource_name): """ Load the specified resource from storage. @param resource_name: Name of the selected resource. @type resource_name: string @return A Python dictionary representation or None if not found. @rtype dict """ resources = ResourceStorage.gql("WHERE name = :1", resource_name) resource = resources[0] return json.loads(resource.data)
def __process_post(self, is_code, prefix): """ Process a POST request. The only allowed POST requests to code are requests to the base URI of a component. This creates a new resource. Same with spezialiced code. @param is_code: Indicates whether this is a request for un-specialized code. @type is_code: boolean @param prefix: The prefix for this type of request. @type prefix: string @return: HTTP return structure. @rtype: Result """ if is_code: # If we are dealing with actual components then the path of this request # here is the correct path to find the component class. component_path = self.request.getRequestPath() specialized_code_name = None specialized_code = None else: # But if we are dealing with specialized components then we first need to # retrieve the partial resource definition and extract the component path # from there. path_elems = self.request.getRequestPath()[len(prefix):].split("/")[1:] specialized_code_name = path_elems[0] specialized_code = retrieveResourceFromStorage(getResourceUri(specialized_code_name, is_partial=True), only_public=False, is_partial=True) if not specialized_code: return Result.notFound("Cannot find specialized component resource '%s'" % specialized_code_name) component_path = specialized_code["private"]["code_uri"] # # Start by processing and sanity-checking the request. # component = getComponentObjectFromPath(component_path) if not component: return Result.notFound("Unknown component") #component = component_class() body = self.request.getRequestBody() try: param_dict = json.loads(body) except Exception, e: raise RestxException("Malformed request body: " + str(e))
def __process_post(self): """ Process a POST request. The only allowed POST requests to code are requests to the base URI of a component. This creates a new resource. @return: HTTP return structure. @rtype: Result """ # # Start by processing and sanity-checking the request. # component_class = getComponentClass(self.request.getRequestPath()) if not component_class: return Result.notFound("Unknown component") #component = component_class() body = self.request.getRequestBody() try: param_dict = json.loads(body) except Exception, e: raise RestxException("Malformed request body: " + str(e))
class ResourceStorage(FileStorage): """ Implementation of resource storage methods. """ def loadResourceFromStorage(self, resource_name): """ Load the specified resource from storage. @param resource_name: Name of the selected resource. @type resource_name: string @return A Python dictionary representation or None if not found. @rtype dict """ try: buf = self.loadFile(resource_name) except RestxFileNotFoundException, e: return None obj = json.loads(buf) return obj
def _accessComponentService(component, services, complete_resource_def, resource_name, service_name, positional_params, runtime_param_dict, input, request=None, method=None, direct_call=False): """ Passes control to a service method exposed by a component. @param component: An instance of the component. @type component: BaseComponent (object of child class) @param services: Dictionary of services definitions for this component. Can be had by calling _getServices() on the component. But we would need the resource's base URI to get those URIs exported properly. Since we already did this call in process() from where we called this method, we just pass the services dictionary in, rather than calling _getServices() again. @param services: dict @param complete_resource_def: The entire resource definition as it was retrieved from storage. @type complete_resource_def: dict @param resource_name: Name of the resource. This may contain '/' if positional parameters are defined in the URL. @type resource_name: string @param service_name: The name of the requested service @type service_name: string @param positional_params: List of positional parameters. @type positional_params: list @param runtime_param_dict: Dictionary of URL command line arguments. @type runtime_param_dict: dict @param input: Any potential input (came in the request body) @type input: string @param request: HTTP request structure. @type request: RestxHttpRequest @param method: Http method of the request. @type method: HttpMethod @param direct_call: Set this if the function is called directly from another component or piece of code that's not part of RESTx. In that case, it wraps the actual exception in a 'normal' exception and passes it up. That allows the framework code to react differently to exceptions in here than direct-call code. @type direct_call: boolean @return HTTP result structure @rtype Result """ try: service_def = services.get(service_name) if not service_def: raise RestxException("Service '%s' is not available in this resource." % service_name) # # Some runtime parameters may have been provided as arguments on # the URL command line. They need to be processed and added to # the parameters if necessary. # # Parameters may either appear as named arguments after the URL, # like this: http://resource/somename?name1=val1&name2=val2 # # If positional parameters are defined for the service then they # may be extracted from the URL. For example, if the positional # parameters are defined as [ "name1", "name2" ] then the URL can # be this: http://resource/somename/val1/val2/ # With that URL and using the order that's defined in the # positional parameter definition, the values are assigned # like this: name1=val1, name2=val2 # # Parameters specified in the first form (named arguments after '?') # override the same parameters specified in the URL itself. # # Why did we not check for those parameters earlier when the # runtime_param_dict parameter was created before this function # was called? Because we may have been called out of the accessResource() # method, which could possibly use a complete # if positional_params: try: pos_param_def = complete_resource_def['public']['services'][service_name]['positional_params'] except Exception, e: pos_param_def = None if pos_param_def: # Iterating over all the positional parameters that are provided in the URI # There might be some empty ones (when the URL has two // in a row or ends # in a /). In that case, we skip that parameter. pos_def_index = 0 for value in positional_params: if value: pname = pos_param_def[pos_def_index] pos_def_index += 1 # Put the new value in the runtime_parameter_dict, but only if it # doesn't exist there already (parameters specified after a '?' # are in there and they take precedence). if pname not in runtime_param_dict: runtime_param_dict[pname] = value if pos_def_index == len(pos_param_def): # No more positional parameters defined? We will ignore whatever # else is in the URL break runtime_param_def = service_def.get('params') if runtime_param_def: # If the 'allow_params_in_body' flag is set for a service then we # allow runtime parameters to be passed in the request body PUT or POST. # So, if the URL command line parameters are not specified then we # should take the runtime parameters out of the body. # Sanity checking and filling in of defaults for the runtime parameters if service_def.get('allow_params_in_body') and input: # Take the base definition of the parameters from the request body try: base_params = json.loads(input.strip()) input = None # The input is now 'used up' except ValueError, e: # Probably couldn't parse JSON properly. base_param = {} # Load the values from the body into the runtime_param_dict, but # only those which are not defined there yet. This allows the # command line args to overwrite what's specified in the body. for name, value in base_params.items(): if name not in runtime_param_dict: runtime_param_dict[name] = value paramSanityCheck(runtime_param_dict, runtime_param_def, "runtime parameter") fillDefaults(runtime_param_def, runtime_param_dict) convertTypes(runtime_param_def, runtime_param_dict)
if runtime_param_dict: # Merge the runtime parameters with the static parameters # from the resource definition. params.update(runtime_param_dict) component.setBaseCapabilities(BaseCapabilities(component)) # A request header may tell us about the request body type. If it's # JSON then we first convert this to a plain object if request: req_headers = request.getRequestHeaders() if req_headers: ct = req_headers.get("Content-type") if ct and "application/json" in ct: if input: input = json.loads(input) result = serviceMethodProxy(component, service_method, service_name, request, input, params, method) return result else: raise RestxException("Service '%s' is not exposed by this resource." % service_name) except RestxException, e: if direct_call: raise Exception(e.msg) else: raise e def _getResourceDetails(resource_name): """
def _accessComponentService(component, services, complete_resource_def, resource_name, service_name, positional_params, runtime_param_dict, input, request=None, method=None, direct_call=False): """ Passes control to a service method exposed by a component. @param component: An instance of the component. @type component: BaseComponent (object of child class) @param services: Dictionary of services definitions for this component. Can be had by calling _getServices() on the component. But we would need the resource's base URI to get those URIs exported properly. Since we already did this call in process() from where we called this method, we just pass the services dictionary in, rather than calling _getServices() again. @param services: dict @param complete_resource_def: The entire resource definition as it was retrieved from storage. @type complete_resource_def: dict @param resource_name: Name of the resource. This may contain '/' if positional parameters are defined in the URL. @type resource_name: string @param service_name: The name of the requested service @type service_name: string @param positional_params: List of positional parameters. @type positional_params: list @param runtime_param_dict: Dictionary of URL command line arguments. @type runtime_param_dict: dict @param input: Any potential input (came in the request body) @type input: string @param request: HTTP request structure. @type request: RestxHttpRequest @param method: Http method of the request. @type method: HttpMethod @param direct_call: Set this if the function is called directly from another component or piece of code that's not part of RESTx. In that case, it wraps the actual exception in a 'normal' exception and passes it up. That allows the framework code to react differently to exceptions in here than direct-call code. @type direct_call: boolean @return HTTP result structure @rtype Result """ try: service_def = services.get(service_name) if not service_def: raise RestxException( "Service '%s' is not available in this resource." % service_name) # # Some runtime parameters may have been provided as arguments on # the URL command line. They need to be processed and added to # the parameters if necessary. # # Parameters may either appear as named arguments after the URL, # like this: http://resource/somename?name1=val1&name2=val2 # # If positional parameters are defined for the service then they # may be extracted from the URL. For example, if the positional # parameters are defined as [ "name1", "name2" ] then the URL can # be this: http://resource/somename/val1/val2/ # With that URL and using the order that's defined in the # positional parameter definition, the values are assigned # like this: name1=val1, name2=val2 # # Parameters specified in the first form (named arguments after '?') # override the same parameters specified in the URL itself. # # Why did we not check for those parameters earlier when the # runtime_param_dict parameter was created before this function # was called? Because we may have been called out of the accessResource() # method, which could possibly use a complete # if positional_params: try: pos_param_def = complete_resource_def['public']['services'][ service_name]['positional_params'] except Exception, e: pos_param_def = None if pos_param_def: # Iterating over all the positional parameters that are provided in the URI # There might be some empty ones (when the URL has two // in a row or ends # in a /). In that case, we skip that parameter. pos_def_index = 0 for value in positional_params: if value: pname = pos_param_def[pos_def_index] pos_def_index += 1 # Put the new value in the runtime_parameter_dict, but only if it # doesn't exist there already (parameters specified after a '?' # are in there and they take precedence). if pname not in runtime_param_dict: runtime_param_dict[pname] = value if pos_def_index == len(pos_param_def): # No more positional parameters defined? We will ignore whatever # else is in the URL break runtime_param_def = service_def.get('params') if runtime_param_def: # If the 'allow_params_in_body' flag is set for a service then we # allow runtime parameters to be passed in the request body PUT or POST. # So, if the URL command line parameters are not specified then we # should take the runtime parameters out of the body. # Sanity checking and filling in of defaults for the runtime parameters if service_def.get('allow_params_in_body') and input: # Take the base definition of the parameters from the request body try: base_params = json.loads(input.strip()) input = None # The input is now 'used up' except ValueError, e: # Probably couldn't parse JSON properly. base_param = {} # Load the values from the body into the runtime_param_dict, but # only those which are not defined there yet. This allows the # command line args to overwrite what's specified in the body. for name, value in base_params.items(): if name not in runtime_param_dict: runtime_param_dict[name] = value paramSanityCheck(runtime_param_dict, runtime_param_def, "runtime parameter") fillDefaults(runtime_param_def, runtime_param_dict) convertTypes(runtime_param_def, runtime_param_dict)
if runtime_param_dict: # Merge the runtime parameters with the static parameters # from the resource definition. params.update(runtime_param_dict) component.setBaseCapabilities(BaseCapabilities(component)) # A request header may tell us about the request body type. If it's # JSON then we first convert this to a plain object if request: req_headers = request.getRequestHeaders() if req_headers: ct = req_headers.get("Content-type") if ct and "application/json" in ct: if input: input = json.loads(input) result = serviceMethodProxy(component, service_method, service_name, request, input, params, method) return result else: raise RestxException( "Service '%s' is not exposed by this resource." % service_name) except RestxException, e: if direct_call: raise Exception(e.msg) else: raise e