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() + "]"
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