Ejemplo n.º 1
0
    def access(self, method=None):
        """
        Sends the service request to the server.

        @param method:  The HTTP request method. If an input was set then this
                        defaults to POST. If the caller requests anything but
                        PUT or POST with a set input then an exception is raised.
                        If no input was specified then method defaults to GET.
        @type method:   string

        @return:        A status, data tuple for the server's response.
        @rtype:         tuple

        """
        # Check if all mandatory parameters have been set
        all_params = self.get_all_parameters()
        if all_params:
            for name, pdef in all_params.items():
                if pdef.is_required():
                    if name not in self.__param_vals:
                        raise RestxClientException("Required parameter '%s' is missing." % name)

         # Assemble the request URI
        qs = urllib.urlencode(self.__param_vals)
        uri = self.__resource.get_uri() + "/" + self.get_name() + (("?%s" % qs) if qs else "")

        if method is None:
            # Caller didn't specify method, so we set a default one.
            if self.__input_buf:
                method = "POST"
            else:
                method = "GET"
        else:
            # A method was specified by the caller. Do some sanity checking.
            # Specifically: If an input was specified then the method must be
            # either POST or PUT
            method = method.upper()
            if self.__input_buf:
                if method not in ["POST", "PUT"]:
                    raise RestxClientException("Request method must be POST or PUT, because a message body (input) was set.")
            else:
                if method not in ["GET", "HEAD", "OPTIONS", "DELETE"]:
                    if method in ["POST", "PUT"]:
                        raise RestxClientExcetion("Cannot specify POST or PUT request method without setting message body (input).")
                    else:
                        raise RestxClientException("Unknown request method '%s'." % method)

        server       = self.__resource.get_server()
        status, data = server._json_send(uri, data=self.__input_buf, method=method)
        return status, data
Ejemplo n.º 2
0
    def __init__(self, server_uri):
        """
        Initialize the server class.

        Send a request for the base meta information to the
        server and remember some of the information that was
        returned.

        It's important to note that the meta information of
        the server is retrieved and cached once. If this
        information should subsequently change, this server
        object won't know about it.

        @param server_uri:      The full URI of the server.
        @type server_uri:       string

        """
        self.__server_uri    = server_uri

        #
        # Need to extract schema, hostname and port from URI
        #
        parse_result = urlparse.urlparse(server_uri)
        if parse_result.scheme != "http":
            raise RestxClientException("Only 'http' schema is currently supported.")
        if parse_result.path:
            self.__docroot = parse_result.path
        else:
            self.__docroot = ""
        if ":" in parse_result.netloc:
            self.__host, port_str = parse_result.netloc.split(":")
            self.__port = int(port_str)
        else:
            self.__host = parse_result.netloc
            self.__port = 80

        #
        # Get meta info from server and perform some sanity checking
        #
        status, d = self._json_send(self.__docroot + self.__META_URI, status=200)

        try:
            self.__component_uri = d[self.__CODE_URI_KEY]
            self.__doc_uri       = d[self.__DOC_URI_KEY]
            self.__name          = d[self.__NAME_KEY]
            self.__resource_uri  = d[self.__RESOURCE_URI_KEY]
            self.__static_uri    = d[self.__STATIC_URI_KEY]
            self.__version       = d[self.__VERSION_KEY]
        except KeyError, e:
            raise RestxClientException("Server error: Expected key '%s' missing in server meta data." % str(e))
Ejemplo n.º 3
0
    def __init__(self, server, rdesc):
        """
        Create a new resource representation in memomory.

        @param server:      The RESTx server on which the resource resides.
        @type server:       L{RestxServer}

        @param rdesc:       Dictionary describing the server resource. This
                            is the dictionary returned by the server when a
                            reource URI is accessed.
        @type rdesc:        dict

        """
        self.__server = server
        try:
            self.__name = rdesc[self.__NAME_KEY]
            self.__description = rdesc[self.__DESC_KEY]
            self.__uri = rdesc[self.__URI_KEY]
            sdict = rdesc[self.__SERVICES_KEY]

            # Parse the service dictionary and attempt to translate
            # this to a dictionary of proper RestxAccessibleService objects.
            self.__services = dict()
            for sname, sdef in sdict.items():
                self.__services[sname] = RestxAccessibleService(
                    self, sname, sdef)

        except KeyError, e:
            raise RestxClientException(
                "Server error: Expected key '%s' missing in definition of resource '%s'."
                % (str(e), self.__name))
Ejemplo n.º 4
0
    def __init__(self, name, sdesc):
        """
        Create a new service representation in memomory.
        
        @param name:        Name of this service.
        @type name:         string

        @param sdesc:       Dictionary describing the service. This
                            is the dictionary returned by the server when a
                            component or resource is accessed.
        @type sdesc:        dict

        """
        try:
            self.__name              = name
            self.__description       = sdesc[self.__DESC_KEY]
            self.__uri               = sdesc[self.__URI_KEY]
            self.__positional_params = sdesc.get(self.__POSITIONAL_PARAMS_KEY)
            pdict                    = sdesc.get(self.__PARAMS_KEY)

            # Parse the parameter dictionary and attempt to translate
            # this to a dictionary of proper RestxParameter objects.
            if pdict:
                self.__parameters = dict()
                for pname, pdef in pdict.items():
                    self.__parameters[pname] = RestxParameter(pname, pdef)

        except KeyError, e:
            raise RestxClientException("Server error: Expected key '%s' missing in definition of service '%s'." % (str(e), self.__name))
Ejemplo n.º 5
0
    def __init__(self, name, pdef):
        """
        Create a new parameter definition representation in memory.

        @param name:    Name of the parameter.
        @type name:     string

        @param pdef:    Dictionary with parameter definition. This is the
                        dictionary returned by the server when describing
                        a parameter.
        @type pdef:     dict

        """
        try:
            self.__name = name
            self.__desc = pdef[self.__DESC_KEY]
            self.__required = _bool_convert(pdef.get(self.__REQUIRED_KEY, "n"))
            self.__type_str = pdef[self.__TYPE_KEY].lower()

            if self.__type_str not in self.__TYPE_CONVERT:
                raise RestxClientException((
                    "Server error: Type '%s' specified for parameter '%s', which is "
                    + "not supported by this client library.") %
                                           (self.__type_str, self.__name))

            if self.__DEFAULT_KEY in pdef:
                # If a default value was specified, store it converted to
                # to the proper type.
                suitable_types, conversion_function = self.__TYPE_CONVERT[
                    self.__type_str]
                value_str = pdef[self.__DEFAULT_KEY]
                if conversion_function:
                    self.__default_val = conversion_function(value_str)
                else:
                    self.__default_val = value_str
            else:
                if not self.__required:
                    raise RestxClientException(
                        "Server error: No default value specified for optional parameter '%s'."
                        % self.__name)

        except KeyError, e:
            raise RestxClientException(
                "Server error: Expected key '%s' missing in definition of parameter '%s'."
                % (str(e), self.__name))
Ejemplo n.º 6
0
    def __init__(self, server, cdesc):
        """
        Create a new component representation in memomory.

        @param server:      The RESTx server on which the component resides.
        @type server:       L{RestxServer}

        @param cdesc:       Dictionary describing the server component. This
                            is the dictionary returned by the server when a
                            component URI is accessed.
        @type cdesc:        dict

        """
        self.__server = server
        try:
            self.__name = cdesc[self.__NAME_KEY]
            self.__description = cdesc[self.__DESC_KEY]
            self.__doc_uri = cdesc[self.__DOC_KEY]
            self.__uri = cdesc[self.__URI_KEY]
            pdict = cdesc[self.__PARAMS_KEY]
            sdict = cdesc[self.__SERVICES_KEY]

            # Parse the parameter dictionary and attempt to translate
            # this to a dictionary of proper RestxParameter objects.
            self.__parameters = dict()
            for pname, pdef in pdict.items():
                self.__parameters[pname] = RestxParameter(pname, pdef)

            # Set the resource creation time parameters, which
            # are always the same for every component. When we
            # create those parameter definitions we specify the
            # dictionary key as the name of the parameter, don't
            # be surprised...
            self.__rcp_description_param = RestxParameter(
                self.__RCP_DESC_KEY,
                cdesc[self.__RCP_KEY][self.__RCP_DESC_KEY])
            self.__rcp_suggested_name_param = RestxParameter(
                self.__RCP_SUGGESTED_NAME_KEY,
                cdesc[self.__RCP_KEY][self.__RCP_SUGGESTED_NAME_KEY])

            # Parse the service dictionary and attempt to translate
            # this to a dictionary of proper RestxService objects.
            self.__services = dict()
            for sname, sdef in sdict.items():
                self.__services[sname] = RestxService(sname, sdef)

        except KeyError:
            raise RestxClientException(
                "Server error: Expected key '%s' missing in definition of component '%s'."
                % (str(e), self.__name))
Ejemplo n.º 7
0
    def create_resource(self):
        """
        Posts a new resource description to the server.

        Returns an initialized L{RestxResource} object, ready to use.

        """
        # Check if all mandatory parameters have been set
        for name, pdef in self.get_all_parameters().items():
            if pdef.is_required():
                if name not in self.__param_values:
                    raise RestxClientException("Required parameter '%s' is missing." % name)

        d = dict()
        d[self.__PARAMS_KEY] = self.__param_values
        d[self.__RCP_KEY]    = self.__resource_creation_param_values

        res = self.__component._create_resource(d)
        if res['status'] != "created":
            raise RestxClientException("Resource could not be created.")

        name = res['name']

        return self.__component.get_server().get_resource(name)
Ejemplo n.º 8
0
    def get_service(self, name):
        """
        Return one service of this component.

        @param name:    Name of the service.
        @type name:     string

        @return:        Dictionary of service definition.
        @rtype:         L{RestxService}

        """
        try:
            return self.__services[name]
        except KeyError:
            raise RestxClientException("Service '%s' not defined." % name)
Ejemplo n.º 9
0
    def get_parameter(self, name):
        """
        Return one parameters of this component.

        @param name:    Name of the parameter.
        @type name:     string

        @return:        Dictionary of all parameters.
        @rtype:         L{RestxParameter}

        """
        try:
            return self.__parameters[name]
        except KeyError:
            raise RestxClientException("Parameter '%s' not defined." % name)
Ejemplo n.º 10
0
    def set_suggested_name(self, name):
        """
        Sets the 'suggested name' resource creation time parameter.

        @param name:    Suggested name for the new resource.
        @type name:     string

        @return:        Reference to ourselves, so that set() calls can be chained
        @rtype:         L{RestxResourceTemplate}

        """
        if type(name) not in [ str, unicode ]:
            raise RestxClientException("Suggested name needs to be of type string or unicode, not '%s'." % type(name))
        self.__resource_creation_param_values[self.__RCP_SUGGESTED_NAME_KEY] = name

        return self
Ejemplo n.º 11
0
    def set_description(self, desc):
        """
        Sets the 'description' resource creation time parameter.

        @param desc:    Description for the new resource.
        @type desc:     string

        @return:        Reference to ourselves, so that set() calls can be chained
        @rtype:         L{RestxResourceTemplate}

        """
        if type(desc) not in [ str, unicode ]:
            raise RestxClientException("Description needs to be of type string or unicode, not '%s'." % type(desc))
        self.__resource_creation_param_values[self.__RCP_DESC_KEY] = desc

        return self
Ejemplo n.º 12
0
    def sanity_check(self, value):
        """
        Check whether this is a valid value for this parameter.

        Raises an exception if there's a problem.

        @param value:      Some value object.
        @type value:       object

        """
        suitable_types, conversion_function = self.__TYPE_CONVERT[
            self.__type_str]
        if type(value) not in suitable_types:
            raise RestxClientException(
                "Type '%s' is not suitable for parameter '%s'. Has to be one of '%s'."
                % (type(value), self.__name, suitable_types))
Ejemplo n.º 13
0
    def _send(self, url, data=None, method=None, status=None, headers=None):
        """
        A sending method that uses our own URL opener.

        Note that we will send all messages with application/json as
        the accept header. JSON is our preferred mode of serializing
        data.

        @param url:     The relative (!) URL on that server to which
                        the request shoudl be sent.
        @type url:      string

        @param data:    Any data object, which will be serialized to
                        JSON if specified.
        @type data:     object

        @param method:  The HTTP request method. Defaults to GET if
                        no data was specified, otherwise POST.
        @type method:   string

        @param status:  Specify the status code that we expect to see.
                        If None, all status codes are allowed. Otherwise
                        the received status code is compared and an
                        exception is thrown if it's not a match.
        @type status:   int

        @param headers: Additional headers that we want to send with the
                        request.
        @type headers:  dict

        @return:        Any data that may have been received from the
                        server.
        @rtype:         string

        """
        if not method:
            # Setting default HTTP method
            if data is None:
                method = "GET"
            else:
                method = "POST"
            
        # Combine default headers with any additional headers
        if not headers:
            headers = self.__DEFAULT_REQ_HEADERS
        else:
            combined_headers = dict()
            combined_headers.update(headers)
            for name, value in self.__DEFAULT_REQ_HEADERS.items():
                combined_headers[name] = value
            headers = combined_headers

        if data:
            headers["Content-length"] = len(data)

        server_conn = httplib.HTTPConnection(self.__host, self.__port)
        server_conn.request(method, url, body=data, headers=headers)

        r = server_conn.getresponse()

        if status is not None:
            if status != r.status:
                r.read()    # Empty the input stream (if we don't do that the next request will be confused)
                raise RestxClientException("Status code %s was expected for request to '%s'. Instead we received %s." % (status, url, r.status))

        data = r.read()
        server_conn.close()
        
        return r.status, data