示例#1
0
class MessageQueue(IConfigurable, IReferenceable, IMessageQueue):
    """
    Abstract message queue.

    Abstract message queue that is used as a basis for specific message queue implementations.

    ### Configuration parameters ###

        - name:                        name of the message queue
        - connection(s):
            - discovery_key:             key to retrieve parameters from discovery service
            - protocol:                  connection protocol like http, https, tcp, udp
            - host:                      host name or IP address
            - port:                      port number
            - uri:                       resource URI or connection string with all parameters in it
        - credential(s):
        - store_key:                 key to retrieve parameters from credential store
        - username:                  user name
        - password:                  user password
        - access_id:                 application access id
        - access_key:                application secret key

    ### References ###

        - *:logger:*:*:1.0           (optional) ILogger components to pass log messages
        - *:counters:*:*:1.0         (optional) ICounters components to pass collected measurements
        - *:discovery:*:*:1.0        (optional) IDiscovery components to discover connection(s)
        - *:credential-store:*:*:1.0 (optional) ICredentialStore componetns to lookup credential(s)
    """
    _name = None
    _capabilities = None
    _lock = None
    _logger = None
    _counters = None
    _credential_resolver = None
    _connection_resolver = None

    def __init__(self, name=None):
        """
        Creates a new instance of the message queue.

        :param name: (optional) a queue name
        """
        self._lock = threading.Lock()
        self._logger = CompositeLogger()
        self._counters = CompositeCounters()
        self._connection_resolver = ConnectionResolver()
        self._credential_resolver = CredentialResolver()
        self._name = name

    def configure(self, config):
        """
        Configures component by passing configuration parameters.

        :param config: configuration parameters to be set.
        """
        self._name = NameResolver.resolve(config)
        self._logger.configure(config)
        self._credential_resolver.configure(config)
        self._connection_resolver.configure(config)

    def set_references(self, references):
        """
        Sets references to dependent components.

        :param references: references to locate the component dependencies.
        """
        self._logger.set_references(references)
        self._counters.set_references(references)
        self._credential_resolver.set_references(references)
        self._connection_resolver.set_references(references)

    def open(self, correlation_id):
        """
        Opens the component.

        :param correlation_id: (optional) transaction id to trace execution through call chain.
        """
        connection = self._connection_resolver.resolve(correlation_id)
        credential = self._credential_resolver.lookup(correlation_id)
        self._open_with_params(correlation_id, connection, credential)

    def _open_with_params(self, correlation_id, connection, credential):
        """
        Opens the component with given connection and credential parameters.

        :param correlation_id: (optional) transaction id to trace execution through call chain.

        :param connection: connection parameters

        :param credential: credential parameters
        """
        raise NotImplementedError('Abstract method that shall be overriden')

    def get_name(self):
        """
        Gets the queue name

        :return: the queue name.
        """
        return self._name if self._name != None else "undefined"

    def get_capabilities(self):
        """
        Gets the queue capabilities

        :return: the queue's capabilities object.
        """
        return self._capabilities

    def send_as_object(self, correlation_id, message_type, message):
        """
        Sends an object into the queue.
        Before sending the object is converted into JSON string and wrapped in a [[MessageEnvelop]].

        :param correlation_id: (optional) transaction id to trace execution through call chain.

        :param message_type: a message type

        :param message: an object value to be sent
        """
        envelop = MessageEnvelop(correlation_id, message_type, message)
        self.send(correlation_id, envelop)

    def begin_listen(self, correlation_id, receiver):
        """
        Listens for incoming messages without blocking the current thread.

        :param correlation_id: (optional) transaction id to trace execution through call chain.

        :param receiver: a receiver to receive incoming messages.
        """
        # Start listening on a parallel tread
        thread = threading.Thread(target=self.listen,
                                  args=(correlation_id, receiver))
        thread.daemon = True
        thread.start()

    def __str__(self):
        """
        Gets a string representation of the object.

        :return: a string representation of the object.
        """
        return "[" + self.get_name() + "]"
示例#2
0
class CompositeConnectionResolver(IReferenceable, IConfigurable):
    """
    Helper class that resolves connection and credential parameters,
    validates them and generates connection options.

    ### Configuration parameters ###
        - connection(s):
            - discovery_key:               (optional) a key to retrieve the connection from :class:`IDiscovery <pip_services3_components.connect.IDiscovery.IDiscovery>`
            - protocol:                    communication protocol
            - host:                        host name or IP address
            - port:                        port number
            - uri:                         resource URI or connection string with all parameters in it
        - credential(s):
            - store_key:                   (optional) a key to retrieve the credentials from :class:`ICredentialStore <pip_services3_components.auth.ICredentialStore.ICredentialStore>`
            - username:                    user name
            - password:                    user password

    ### References ###
        - `\*:discovery:\*:\*:1.0`         (optional) :class:`IDiscovery <pip_services3_components.connect.IDiscovery.IDiscovery>` services to resolve connections
        - `\*:credential-store:\*:\*:1.0`  (optional) Credential stores to resolve credentials
    """
    def __init__(self):
        super(CompositeConnectionResolver, self).__init__()

        # The connection options
        self._options: ConfigParams = None

        # The connections resolver.
        self._connection_resolver = ConnectionResolver()

        # The credentials resolver.
        self._credential_resolver = CredentialResolver()

        # The cluster support (multiple connections)
        self._cluster_supported = True

        # The default protocol
        self._default_protocol: str = None

        # The default port number
        self._default_port: int = 0

        # The list of supported protocols
        self._supported_protocols: List[str] = []

    def configure(self, config: ConfigParams):
        """
        Configures component by passing configuration parameters.

        :param config: configuration parameters to be set.
        """
        self._connection_resolver.configure(config)
        self._credential_resolver.configure(config)
        self._options = config.get_section('options')

    def set_references(self, references: IReferences):
        """
        Sets references to dependent components.

        :param references: references to locate the component dependencies.
        """
        self._connection_resolver.set_references(references)
        self._credential_resolver.set_references(references)

    def resolve(self, correlation_id: Optional[str]) -> ConfigParams:
        """
        Resolves connection options from connection and credential parameters.

        :param correlation_id: (optional) transaction id to trace execution through call chain.
        :return: resolved options or error
        """

        connections = self._connection_resolver.resolve_all(correlation_id)

        if len(connections) > 0 and not self._cluster_supported:
            raise ConfigException(
                correlation_id, "MULTIPLE_CONNECTIONS_NOT_SUPPORTED",
                "Multiple (cluster) connections are not supported")

        # Validate connections
        for connection in connections:
            self._validate_connection(correlation_id, connection)

        credential = self._credential_resolver.lookup(correlation_id)
        # Validate credential
        self._validate_credential(correlation_id, credential)

        options = self._compose_options(connections, credential, self._options)

        return options

    def compose(self, correlation_id: Optional[str],
                connections: List[ConnectionParams],
                credential: CredentialParams,
                parameters: ConfigParams) -> ConfigParams:
        """
        Composes Composite connection options from connection and credential parameters.

        :param correlation_id:  (optional) transaction id to trace execution through call chain.
        :param connections:    connection parameters
        :param credential:     credential parameters
        :param parameters:     optional parameters
        :return:               resolved options or error.
        """
        # Validate connection parameters
        for connection in connections:
            self._validate_connection(correlation_id, connection)

        # Validate credential parameters
        self._validate_credential(correlation_id, credential)

        options = self._compose_options(connections, credential, parameters)

        return options

    def _validate_connection(self, correlation_id: Optional[str],
                             connection: ConnectionParams):
        """
        Validates connection parameters.
        This method can be overriden in child classes.

        :param correlation_id:  (optional) transaction id to trace execution through call chain.
        :param connection:      connection parameters to be validated
        :return:                error or `None` if validation was successful
        """

        if connection is None:
            raise ConfigException(
                correlation_id, "NO_CONNECTION",
                "Connection parameters are not set is not set")

        # URI usually contains all information
        uri = connection.get_uri()
        if uri is not None: return None

        protocol = connection.get_protocol_with_default(self._default_protocol)
        if protocol is None:
            raise ConfigException(correlation_id, "NO_PROTOCOL",
                                  "Connection protocol is not set")

        if self._supported_protocols is not None and protocol in self._supported_protocols:
            raise ConfigException(
                correlation_id, "UNSUPPORTED_PROTOCOL",
                "The protocol " + protocol + " is not supported")

        host = connection.get_host()
        if host is None:
            raise ConfigException(correlation_id, "NO_HOST",
                                  "Connection host is not set")

        port = connection.get_port_with_default(self._default_port)
        if port == 0:
            raise ConfigException(correlation_id, "NO_PORT",
                                  "Connection port is not set")

        return None

    def _validate_credential(self, correlation_id: Optional[str],
                             credential: CredentialParams):
        """
        Validates credential parameters.
        This method can be overriden in child classes.

        :param correlation_id:  (optional) transaction id to trace execution through call chain.
        :param credential:      credential parameters to be validated
        :return:                error or `None` if validation was successful
        """
        return None

    def _compose_options(self, connections: List[ConnectionParams],
                         credential: CredentialParams,
                         parameters: ConfigParams) -> ConfigParams:
        # Connection options
        options = ConfigParams()

        # Merge connection parameters
        for connection in connections:
            options = self._merge_connection(options, connection)

        # Merge credential parameters
        options = self._merge_credential(options, credential)

        # Merge optional parameters
        options = self._merge_optional(options, parameters)

        # Perform final processing
        options = self._finalize_options(options)

        return options

    def _merge_connection(self, options: ConfigParams,
                          connection: ConnectionParams) -> ConfigParams:
        """
        Merges connection options with connection parameters
        This method can be overriden in child classes.

        :param options: connection options
        :param connection: connection parameters to be merged
        :return:  merged connection options.
        """
        merged_options = options.set_defaults(connection)
        return merged_options

    def _merge_credential(self, options: ConfigParams,
                          credential: CredentialParams) -> ConfigParams:
        """
        Merges connection options with credential parameters
        This method can be overriden in child classes.

        :param options:     connection options
        :param credential:  credential parameters to be merged
        :return:            merged connection options.
        """
        merged_options = options.override(credential)
        return merged_options

    def _merge_optional(self, options: ConfigParams,
                        parameters: ConfigParams) -> ConfigParams:
        """
        Merges connection options with optional parameters
        This method can be overriden in child classes.

        :param options: connection options
        :param parameters: optional parameters to be merged
        :return:  merged connection options.
        """
        merged_options = options.override(parameters)
        return merged_options

    def _finalize_options(self, options: ConfigParams) -> ConfigParams:
        """
        Finalize merged options
        This method can be overriden in child classes.

        :param options: connection options
        :return: finalized connection options
        """
        return options