Esempio n. 1
0
    def __init__(self, client_name: str):
        """
        Creates a new instance of the client.

        :param client_name: a client name.
        """
        self.__client = None
        self.__client_name = None

        # The GRPC client channel
        self._channel = None

        # The connection resolver.
        self._connection_resolver = HttpConnectionResolver()

        # The logger.
        self._logger = CompositeLogger()

        # The performance counters.
        self._counters = CompositeCounters()

        # The configuration options.
        self._options = ConfigParams()

        # The connection timeout in milliseconds.
        self._connection_timeout = 100000

        # The invocation timeout in milliseconds.
        self._timeout = 100000

        # The remote service uri which is calculated on open.
        self._uri: str = None

        self.__client_name = client_name
    def __init__(self, service_name: str = None):
        """
        Creates a new instance of the service.

        :param service_name: a service name.
        """
        self.__config: ConfigParams = None
        self.__references: IReferences = None
        self.__local_endpoint: bool = None
        self.__implementation: Any = {}
        self.__interceptors: List[Any] = []
        self.__opened: bool = None

        # The GRPC endpoint that exposes this service.
        self._endpoint: GrpcEndpoint = None

        # The dependency resolver.
        self._dependency_resolver = DependencyResolver(
            GrpcService.__default_config)

        # The logger.
        self._logger = CompositeLogger()

        # The performance counters.
        self._counters = CompositeCounters()

        self.__service_name = service_name
        self.__registrable = lambda implementation: self._register_service(
            implementation)
    def __init__(self):
        """
        Creates a new instance of the connection component.
        """
        self.__default_config = ConfigParams.from_tuples(
            'options.max_pool_size', 2, 'options.keep_alive', 1,
            'options.connect_timeout', 5000, 'options.auto_reconnect', True,
            'options.max_page_size', 100, 'options.debug', True)

        self._logger = CompositeLogger()
        self._connection_resolver = MongoDbConnectionResolver()
        self._options = ConfigParams()
Esempio n. 4
0
 def __init__(self):
     self.__server: Any = None
     self.__connection_resolver = HttpConnectionResolver()
     self.__logger = CompositeLogger()
     self.__counters = CompositeCounters()
     self.__maintenance_enabled = False
     self.__file_max_size = 200 * 1024 * 1024
     self.__uri: str = None
     self.__registrations: List[IRegisterable] = []
     self.__commandable_methods: Any = None
     self.__commandable_schemas: Any = None
     self.__commandable_service: Any = None
     self.__interceptors = []
Esempio n. 5
0
    def __init__(self):
        """
        Creates a new instance of the connection component.
        """
        self.__default_config = ConfigParams.from_tuples(
            'options.max_pool_size', 2,
            'options.connect_timeout', 5000,
            'options.auto_reconnect', True,
            'options.max_page_size', 100,
            'options.debug', True
        )

        # The logger
        self._logger: CompositeLogger = CompositeLogger()
        # The connection resolver
        self._connection_resolver: MongoDbConnectionResolver = MongoDbConnectionResolver()
        # The configuration options.
        self._options: ConfigParams = ConfigParams()
        # The MongoDB connection object.
        self._connection: pymongo.MongoClient = None
        # The MongoDB database name.
        self._database_name: str = None
        # The MongoDb database object.
        self._db: database.Database = None
Esempio n. 6
0
class RestOperations(IConfigurable, IReferenceable, ABC):
    _logger = CompositeLogger()
    _counters = CompositeCounters()
    _dependency_resolver = DependencyResolver()

    def configure(self, config):
        self._dependency_resolver.configure(config)

    def set_references(self, references):
        self._logger.set_references(references)
        self._counters.set_references(references)
        self._dependency_resolver.set_references(references)

    def get_param(self, param, default=None):
        return bottle.request.params.get(param, default)

    def _get_correlation_id(self):
        return bottle.request.query.get('correlation_id')

    def _get_filter_params(self):
        data = dict(bottle.request.query.decode())
        data.pop('correlation_id', None)
        data.pop('skip', None)
        data.pop('take', None)
        data.pop('total', None)
        return FilterParams(data)

    def _get_paging_params(self):
        skip = bottle.request.query.get('skip')
        take = bottle.request.query.get('take')
        total = bottle.request.query.get('total')
        return PagingParams(skip, take, total)

    def _get_data(self):
        data = bottle.request.json
        if isinstance(data, str):
            return json.loads(bottle.request.json)
        elif bottle.request.json:
            return bottle.request.json
        else:
            return None

    # def _get_correlation_id(self, req=None, res=None):
    #     return req.params.correlation_id

    # def _get_filter_params(self, req=None, res=None):
    #     _res = {}
    #     for key in req.query.keys():
    #         if key not in ['skip', 'take', 'total']:
    #             _res[key] = req.query[key]
    #     return FilterParams.from_value(_res)

    # def _get_paging_params(self, req=None, res=None):
    #     _res = {}
    #     for key in req.query.keys():
    #         if key in ['skip', 'take', 'total']:
    #             _res[key] = req.query[key]

    #     return FilterParams.from_value(_res)

    def _send_result(self, res=None):
        return HttpResponseSender.send_result(res)

    def _send_empty_result(self, res=None):
        return HttpResponseSender.send_empty_result(res)

    def _send_created_result(self, res=None):
        return HttpResponseSender.send_created_result(res)

    def _send_deleted_result(self):
        return HttpResponseSender.send_deleted_result()

    def _send_error(self, error=None):
        HttpResponseSender.send_error(error)

    def _send_bad_request(self, req, message):
        correlation_id = self._get_correlation_id(req)
        error = BadRequestException(correlation_id, 'BAD_REQUEST', message)
        self._send_error(error)

    def _send_unauthorized(self, req, message):
        correlation_id = self._get_correlation_id(req)
        error = UnauthorizedException(correlation_id, 'UNAUTHORIZED', message)
        self._send_error(error)

    def _send_not_found(self, req, message):
        correlation_id = self._get_correlation_id(req)
        error = NotFoundException(correlation_id, 'NOT_FOUND', message)
        self._send_error(error)

    def _send_conflict(self, req, message):
        correlation_id = self._get_correlation_id(req)
        error = ConflictException(correlation_id, 'CONFLICT', message)
        self._send_error(error)

    def _send_session_expired(self, req, message):
        correlation_id = self._get_correlation_id(req)
        error = UnknownException(correlation_id, 'SESSION_EXPIRED', message)
        error.status = 440
        self._send_error(error)

    def _send_internal_error(self, req, message):
        correlation_id = self._get_correlation_id(req)
        error = ConflictException(correlation_id, 'SERVER_UNAVAILABLE',
                                  message)
        error.status = 503
        self._send_error(error)

    def invoke(self, operation):
        for attr in dir(self):
            if attr in dir(self):
                return lambda req, res: getattr(self, operation)(req, res)
Esempio n. 7
0
 def __init__(self):
     super().__init__()
     self._logger: CompositeLogger = CompositeLogger()
     self._counters: CompositeCounters = CompositeCounters()
     self._dependency_resolver: DependencyResolver = DependencyResolver()
Esempio n. 8
0
class GrpcEndpoint(IOpenable, IConfigurable, IReferenceable):
    """
    Used for creating GRPC endpoints. An endpoint is a URL, at which a given service can be accessed by a client.

    ### Configuration parameters ###

    Parameters to pass to the [[configure]] method for component configuration:

    - connection(s) - the connection resolver's connections:
        - "connection.discovery_key" - the key to use for connection resolving in a discovery service;
        - "connection.protocol" - the connection's protocol;
        - "connection.host" - the target host;
        - "connection.port" - the target port;
        - "connection.uri" - the target URI.
    - credential - the HTTPS credentials:
        - "credential.ssl_key_file" - the SSL private key in PEM
        - "credential.ssl_crt_file" - the SSL certificate in PEM
        - "credential.ssl_ca_file" - the certificate authorities (root cerfiticates) in PEM

    ### References ###

    A logger, counters, and a connection resolver can be referenced by passing the
    following references to the object's [[setReferences]] method:

    - logger: <code>"\*:logger:\*:\*:1.0"</code>;
    - counters: <code>"\*:counters:\*:\*:1.0"</code>;
    - discovery: <code>"\*:discovery:\*:\*:1.0"</code> (for the connection resolver).

    ### Examples ###
        TODO!!!

    """

    __defaultConfig = ConfigParams.from_tuples(
        "connection.protocol", "http",
        "connection.host", "0.0.0.0",
        "connection.port", 3000,

        "credential.ssl_key_file", None,
        "credential.ssl_crt_file", None,
        "credential.ssl_ca_file", None,

        "options.maintenance_enabled", None,
        "options.request_max_size", 1024 * 1024,
        "options.file_max_size", 200 * 1024 * 1024,
        "options.connect_timeout", 60000,
        "options.debug", None
    )

    __server = None
    __connection_resolver = HttpConnectionResolver()
    __logger = CompositeLogger()
    __counters = CompositeCounters()
    __maintenance_enabled = False
    __file_max_size = 200 * 1024 * 1024
    __uri = None
    __registrations = []
    __commandable_methods = None
    __commandable_schemas = None
    __commandable_service = None
    __interceptors = []

    def configure(self, config):
        """
        Configures this HttpEndpoint using the given configuration parameters.

        __Configuration parameters:__
        - __connection(s)__ - the connection resolver's connections;
        - "connection.discovery_key" - the key to use for connection resolving in a dis
        - "connection.protocol" - the connection's protocol;
        - "connection.host" - the target host;
        - "connection.port" - the target port;
        - "connection.uri" - the target URI.
        - "credential.ssl_key_file" - SSL private key in PEM
        - "credential.ssl_crt_file" - SSL certificate in PEM
        - "credential.ssl_ca_file" - Certificate authority (root certificate) in PEM

        :param config: configuration parameters, containing a "connection(s)" section.
        """
        config = config.set_defaults(GrpcEndpoint.__defaultConfig)
        self.__connection_resolver.configure(config)

        self.__maintenance_enabled = config.get_as_boolean_with_default('options.maintenance_enabled',
                                                                        self.__maintenance_enabled)
        self.__file_max_size = ConfigParams().get_as_long_with_default(key='options.file_max_size',
                                                                       default_value=self.__file_max_size)

    def set_references(self, references):
        """
        Sets references to this endpoint's logger, counters, and connection resolver.

        __References:__
        - logger: <code>"\*:logger:\*:\*:1.0"</code>
        - counters: <code>"\*:counters:\*:\*:1.0"</code>
        - discovery: <code>"\*:discovery:\*:\*:1.0"</code> (for the connection resolver)

        :param references: an IReferences object, containing references to a logger, counters,
                           and a connection resolver.
        """
        self.__logger.set_references(references)
        self.__counters.set_references(references)
        self.__connection_resolver.set_references(references)

    def is_open(self):
        """
        :return: whether or not this endpoint is open with an actively listening GRPC server.
        """
        return self.__server is not None

    def open(self, correlation_id, max_workers=15):
        """
        Opens a connection using the parameters resolved by the referenced connection
        resolver and creates a GRPC server (service) using the set options and parameters.

        :param correlation_id: (optional) transaction id to trace execution through call chain.
        :param max_workers: max count of workers in thread pool.
        """
        if self.is_open():
            return

        connection = self.__connection_resolver.resolve(correlation_id)
        self.__uri = connection.get_uri()
        try:
            self.__connection_resolver.register(correlation_id)

            credentials = None

            if connection.get_protocol('http') == 'https':
                ssl_key_file = connection.get_as_nullable_string('ssl_key_file')
                ssl_crt_file = connection.get_as_nullable_string('ssl_crt_file')

                with open(ssl_key_file, 'rb') as file:
                    private_key = file.read()

                with open(ssl_crt_file, 'rb') as file:
                    certificate = file.read()

                credentials = grpc.ssl_server_credentials(((private_key, certificate),))

            # Create instance of express application
            if len(self.__interceptors) > 0:
                self.__server = grpc.server(futures.ThreadPoolExecutor(max_workers=max_workers),
                                            interceptors=self.__interceptors)
            else:
                self.__server = grpc.server(futures.ThreadPoolExecutor(max_workers=max_workers))

            if credentials:
                self.__server.add_secure_port(str(connection.get_host()) + ':' +
                                              str(connection.get_port()), credentials)
            else:
                self.__server.add_insecure_port(str(connection.get_host()) + ':' + str(connection.get_port()))
            # Start operations
            self.__server.start()
            self.__connection_resolver.register(correlation_id)
            self.__perform_registrations()
            self.__logger.debug(correlation_id, 'Opened GRPC service at {}'.format(self.__uri))

        except Exception as ex:
            self.__server = None
            err = ConnectionException(correlation_id, 'CANNOT_CONNECT', 'Opening GRPC service failed').wrap(
                ex).with_details('url', self.__uri)
            raise err

    def close(self, correlation_id):
        """
        Closes this endpoint and the GRPC server (service) that was opened earlier.
        :param correlation_id: (optional) transaction id to trace execution through call chain.
        """
        if self.__server is not None:
            self.__uri = None
            self.__commandable_methods = None
            self.__commandable_schemas = None
            self.__commandable_service = None

            # Eat exceptions
            try:
                self.__server.stop(None)
                self.__logger.debug(correlation_id, 'Closed GRPC service at {}'.format(self.__uri))
                self.__server = None
                GrpcEndpoint.__interceptors = []
                GrpcEndpoint.__registrations = []
                GrpcEndpoint.__connection_resolver = HttpConnectionResolver()
            except Exception as ex:
                self.__logger.warn(correlation_id, 'Failed while closing GRPC service: '.format(ex))

    def register(self, registration):
        """
        Registers a registerable object for dynamic endpoint discovery.

        :param registration: the registration to add.
        :return:
        """
        if registration is not None:
            self.__registrations.append(registration)

    def unregister(self, registration):
        """
        Unregisters a registerable object, so that it is no longer used in dynamic
        endpoint discovery.

        :param registration: the registration to remove.
        """
        self.__registrations = list(filter(lambda r: r == registration, self.__registrations))

    def __perform_registrations(self):
        for registration in self.__registrations:
            registration.register()

        self.__register_commandable_service()

    def __register_commandable_service(self):
        if self.__commandable_methods is None:
            return
        self.__commandable_service = _CommandableMediator()
        self.__commandable_service.invoke_func(self.__invoke_commandable_method)

        self.register_service(self.__commandable_service)

    def __invoke_commandable_method(self, request, context):
        method = request.method
        action = self.__commandable_methods[method] if self.__commandable_methods else None
        correlation_id = request.correlation_id
        response = commandable_pb2.InvokeReply()

        # Handle method not found
        if action is None:
            err = InvocationException(correlation_id, 'METHOD_NOT_FOUND',
                                      'Method ' + method + ' was not found').with_details('method', method)
            resp_err = ErrorDescriptionFactory.create(err)
            response.error = commandable_pb2.ErrorDescription()
            response.error.category = resp_err.category
            response.error.code = resp_err.code
            response.error.correlation_id = resp_err.correlation_id
            response.error.status = resp_err.status
            response.error.message = resp_err.message
            response.error.cause = resp_err.cause
            response.error.stack_trace = resp_err.stack_trace
            response.error.details.addAll(resp_err.details)
            response.resultEmpty = True
            response.resultJson = ''

            return response

        try:
            # Convert arguments
            args_empty = request.args_empty
            args_json = request.args_json
            args = Parameters.from_json(args_json) if not args_empty and args_json else Parameters()

            try:
                result = action(correlation_id, args, method)
                response.result_empty = result is None
                if type(result) is DataPage:
                    response.result_json = json.dumps(result.to_json())
                else:
                    response.result_json = json.dumps(result) if result is not None else ''

                # TODO: Validate schema
                schema = self.__commandable_schemas[method]
                if schema:
                    pass

            except Exception as ex:
                # Process result and generate response
                resp_err = ErrorDescriptionFactory.create(ex)
                response.error.category = resp_err.category
                response.error.code = resp_err.code
                response.error.correlation_id = resp_err.correlation_id
                response.error.status = resp_err.status
                response.error.message = resp_err.message
                response.error.cause = resp_err.cause
                response.error.stack_trace = resp_err.stack_trace
                response.error.details.update(resp_err.details)
                response.result_empty = True
                response.result_json = ''

        except Exception as ex:
            # Handle unexpected exception
            err = InvocationException(correlation_id, 'METHOD_FAILED', 'Method ' + method + ' failed').wrap(
                ex).with_details('method', method)
            resp_err = ErrorDescriptionFactory.create(err)
            response.error.category = resp_err.category
            response.error.code = resp_err.code
            response.error.correlation_id = resp_err.correlation_id
            response.error.status = resp_err.status
            response.error.message = resp_err.message
            response.error.cause = resp_err.cause
            response.error.stack_trace = resp_err.stack_trace
            response.error.details.update(resp_err.details)
            response.result_empty = True
            response.result_json = ''

        return response

    def register_service(self, service):
        """
        Registers a service with related implementation
        :param service: a GRPC service object.
        """
        service.add_servicer_to_server(self.__server)

    def register_commandable_method(self, method, schema, action):
        """
        Registers a commandable method in this objects GRPC server (service) by the given name.,

        :param method: the GRPC method name.
        :param schema: the schema to use for parameter validation.
        :param action: the action to perform at the given route.
        """
        self.__commandable_methods = self.__commandable_methods or {}
        self.__commandable_methods[method] = action

        self.__commandable_schemas = self.__commandable_schemas or {}
        self.__commandable_schemas[method] = schema

    def register_interceptor(self, interceptor):
        self.__interceptors.append(interceptor)
Esempio n. 9
0
class GrpcService(IOpenable, IConfigurable, IRegisterable, IUnreferenceable):
    """
    Abstract service that receives remove calls via GRPC protocol.

    ### Configuration parameters ###

    - dependencies:
      - endpoint:              override for GRPC Endpoint dependency
      - controller:            override for Controller dependency
    - connection(s):
      - discovery_key:         (optional) a key to retrieve the connection from [[https://rawgit.com/pip-services-node/pip-services3-components-node/master/doc/api/interfaces/connect.idiscovery.html IDiscovery]]
      - protocol:              connection protocol: http or https
      - host:                  host name or IP address
      - port:                  port number
      - uri:                   resource URI or connection string with all parameters in it
    - credential - the HTTPS credentials:
      - ssl_key_file:         the SSL private key in PEM
      - ssl_crt_file:         the SSL certificate in PEM
      - ssl_ca_file:          the certificate authorities (root cerfiticates) in PEM



    ### Example ###
        TODO!!!

    """

    __default_config = ConfigParams.from_tuples("dependencies.endpoint",
                                                "*:endpoint:grpc:*:1.0")
    __service_name = None
    __config = None
    __references = None
    __local_endpoint = None
    __registrable = None
    __implementation = {}
    __interceptors = []
    __opened = None

    # The GRPC endpoint that exposes this service.
    _endpoint = None

    # The dependency resolver.
    _dependency_resolver = DependencyResolver(__default_config)

    # The logger.
    _logger = CompositeLogger()

    # The performance counters.
    _counters = CompositeCounters()

    def __init__(self, service_name=None):
        self.__service_name = service_name
        self.__registrable = lambda: self._register_service()

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

        config = config.set_defaults(GrpcService.__default_config)
        self.__config = config
        self._dependency_resolver.configure(config)

    def set_references(self, references):
        """
        Sets references to this endpoint's logger, counters, and connection resolver.
        __References:__
        - logger: <code>"\*:logger:\*:\*:1.0"</code>
        - counters: <code>"\*:counters:\*:\*:1.0"</code>
        - discovery: <code>"\*:discovery:\*:\*:1.0"</code> (for the connection resolver)

        :param references: an IReferences object, containing references to a logger, counters,
                           and a connection resolver.
        """
        self._logger.set_references(references)
        self._counters.set_references(references)
        self._dependency_resolver.set_references(references)

        # Get endpoint
        self._endpoint = self._dependency_resolver.get_one_optional('endpoint')

        # Or create a local one
        if self._endpoint is None:
            self._endpoint = self.__create_endpoint()
            self.__local_endpoint = True
        else:
            self.__local_endpoint = False

        #  Add registration callback to the endpoint
        self._endpoint.register(self)

    def unset_references(self):
        """
        Unsets (clears) previously set references to dependent components.
        """
        # Remove registration callback from endpoint
        if self._endpoint is not None:
            self._endpoint.unregister(self.__registrable)
            self._endpoint = None

    def __create_endpoint(self):
        endpoint = GrpcEndpoint()

        if self.__config:
            endpoint.configure(self.__config)
        if self.__references:
            endpoint.set_references(self.__references)

        return endpoint

    def _instrument(self, correlation_id, name):
        """
        Adds instrumentation to log calls and measure call time.
        It returns a Timing object that is used to end the time measurement.

        :param correlation_id: (optional) transaction id to trace execution through call chain.
        :param name: a method name.
        :return: Timing object to end the time measurement.
        """
        self._logger.trace(correlation_id, 'Executing {} method'.format(name))
        self._counters.increment_one(name + '.exec_time')
        return self._counters.begin_timing(name + '.exec_time')

    def _instrument_error(self, correlation_id, name, err, reerror=False):
        if err is not None:
            self._logger.error(correlation_id, err,
                               'Failed to execute {} method'.format(name))
            self._counters.increment_one(name + '.exec_errors')

        if reerror:
            raise reerror

    def is_open(self):
        """
        Checks if the component is opened.

        :return: true if the component has been opened and false otherwise.
        """
        return self.__opened

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

        :param correlation_id: (optional) transaction id to trace execution through call chain.
        :param callback: callback function that receives error or null no errors occured.
        """
        # TODO maybe need add async

        if self.__opened:
            return None

        if self._endpoint is None:
            self._endpoint = self.__create_endpoint()
            self._endpoint.register(self)
            self.__local_endpoint = True

        if self.__local_endpoint:
            try:
                self._endpoint.open(correlation_id)
                self.__opened = True
            except Exception as ex:
                self.__opened = False
                raise ex
        else:
            self.__opened = True

    def close(self, correlation_id):
        """
        Closes component and frees used resources.

        :param correlation_id: (optional) transaction id to trace execution through call chain.
        :param callback: callback function that receives error or null no errors occured.
        """
        if not self.__opened:
            return None

        if self._endpoint is None:
            raise InvalidStateException(correlation_id, 'NO_ENDPOINT',
                                        'HTTP endpoint is missing')

        if self.__local_endpoint:
            self._endpoint.close(correlation_id)

        self.__opened = False

    def register_commadable_method(self, method, schema, action):
        self._endpoint.register_commandable_method(method, schema, action)

    def _register_interceptor(self, action):
        if self._endpoint is not None:
            self._endpoint.register_interceptor(action)

    def _register_service(self, implementation):
        # self.register()

        if self._endpoint is not None:
            self._endpoint.register_service(implementation)

    def register(self):
        """
Esempio n. 10
0
class GrpcClient(IOpenable, IReferenceable, IConfigurable):
    """
    Abstract client that calls remove endpoints using GRPC protocol.

    ### Configuration parameters ###

    - connection(s):
      - discovery_key:         (optional) a key to retrieve the connection from [[link]]
      - protocol:              connection protocol: http or https
      - host:                  host name or IP address
      - port:                  port number
      - uri:                   resource URI or connection string with all parameters in it
    - options:
      - retries:               number of retries (default: 3)
      - connect_timeout:       connection timeout in milliseconds (default: 10 sec)
      - timeout:               invocation timeout in milliseconds (default: 10 sec)
    # TODO description
    """

    _default_config = ConfigParams.from_tuples(
        "connection.protocol", "http", "connection.host", "0.0.0.0",
        "connection.port", 3000, "options.request_max_size", 1024 * 1024,
        "options.connect_timeout", 10000, "options.timeout", 10000,
        "options.retries", 3, "options.debug", True)

    __client = None
    __client_name = None

    # The GRPC client chanel
    __channel = None

    # The connection resolver.
    __connetction_resolver = HttpConnectionResolver()

    # The logger.
    __logger = CompositeLogger()

    # The performance counters.
    __counters = CompositeCounters()

    # The configuration options.
    __options = ConfigParams()

    # The connection timeout in milliseconds.
    __connection_timeout = 100000

    # The invocation timeout in milliseconds.
    __timeout = 100000

    # The remote service uri which is calculated on open.
    __uri = None

    def __init__(self, client_name):
        self.__client_name = client_name

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

        :param config: configuration parameters to be set.
        """
        config = config.set_defaults(GrpcClient._default_config)
        self.__connetction_resolver.configure(config)
        self.__options = self.__options.override(config.get_section('options'))

        self.__connection_timeout = config.get_as_integer_with_default(
            'options.connect_timeout', self.__connection_timeout)
        self.__timeout = config.get_as_integer_with_default(
            'options.timeout', self.__timeout)

    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.__connetction_resolver.set_references(references)

    def _instrument(self, correlation_id, name):
        """
        Adds instrumentation to log calls and measure call time.
        It returns a Timing object that is used to end the time measurement.

        :param correlation_id: (optional) transaction id to trace execution through call chain.
        :param name: a method name.
        :return: Timing object to end the time measurement.
        """
        self.__logger.trace(correlation_id, 'Executing {} method'.format(name))
        self.__counters.increment_one(name + '.call_count')
        return self.__counters.begin_timing(name + '.call_time')

    def _instrument_error(self, correlation_id, name, err, reerror=False):
        """
        Adds instrumentation to error handling.

        :param correlation_id: (optional) transaction id to trace execution through call chain.
        :param name: a method name.
        :param err: an occured error
        :param reerror: if true - throw error
        """
        if err is not None:
            self.__logger.error(correlation_id, err,
                                'Failed to call {} method'.format(name))
            self.__counters.increment_one(name + '.call_errors')
            if reerror is not None and reerror is True:
                raise err

    def is_open(self):
        """
        Checks if the component is opened.

        :return: Returns true if the component has been opened and false otherwise.
        """
        return self.__channel is not None

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

        :param correlation_id: (optional) transaction id to trace execution through call chain.
        :return: Future that receives error or null no errors occured.
        """
        if self.is_open():
            return None

        try:
            connection = self.__connetction_resolver.resolve(correlation_id)
            self.__uri = connection.get_uri()

            options = [('grpc.max_connection_idle_ms',
                        self.__connection_timeout),
                       ('grpc.client_idle_timeout_ms', self.__timeout)]

            if connection.get_protocol('http') == 'https':
                ssl_ca_file = connection.get_as_nullable_string('ssl_ca_file')
                with open(ssl_ca_file, 'rb') as file:
                    trusted_root = file.read()
                credentials = grpc.ssl_channel_credentials(trusted_root)
                channel = grpc.secure_channel(str(connection.get_host()) +
                                              ':' + str(connection.get_port()),
                                              credentials=credentials,
                                              options=options)
            else:
                channel = grpc.insecure_channel(str(connection.get_host()) +
                                                ':' +
                                                str(connection.get_port()),
                                                options=options)
            self.__channel = channel

        except Exception as ex:
            raise ConnectionException(
                correlation_id, 'CANNOT_CONNECT',
                'Opening GRPC client failed').wrap(ex).with_details(
                    'url', self.__uri)

    def close(self, correlation_id):
        """
        Closes component and frees used resources.

        :param correlation_id: (optional) transaction id to trace execution through call chain.
        :return: Future that receives error or null no errors occured.
        """
        if self.__channel is not None:
            # Eat exceptions
            try:
                self.__logger.debug(
                    correlation_id,
                    'Closed GRPC service at {}'.format(self.__uri))
            except Exception as ex:
                self.__logger.warn(
                    correlation_id,
                    'Failed while closing GRPC service: {}'.format(ex))
            # if self.__client is not None:
            #     self.__client = None
            self.__channel.close()
            self.__channel = None
            self.__uri = None
            GrpcClient.__connetction_resolver = HttpConnectionResolver()

    def call(self, method, client, request):
        """
        Calls a remote method via GRPC protocol.

        :param client: current client
        :param request: (optional) request object.
        :return: (optional) Future that receives result object or error.
        """

        client = client(self.__channel)
        executor = futures.ThreadPoolExecutor(max_workers=1)
        response = executor.submit(client.__dict__[method], request).result()
        # TODO: check this realization

        return response

    def add_filter_params(self, params, filter):
        """
        AddFilterParams method are adds filter parameters (with the same name as they defined)
        to invocation parameter map.

        :param params: invocation parameters.
        :param filter: (optional) filter parameters
        :return: invocation parameters with added filter parameters.
        """
        params = StringValueMap() if params is None else params

        if filter is not None:
            for k in filter.keys():
                params.put(k, filter[k])

        return params

    def add_paging_params(self, params, paging):
        """
        AddPagingParams method are adds paging parameters (skip, take, total) to invocation parameter map.
        :param params: invocation parameters.
        :param paging: (optional) paging parameters
        :return: invocation parameters with added paging parameters.
        """
        params = StringValueMap() if params is None else params

        if paging is not None:
            params.put('total', paging.total)
            if paging.skip is not None:
                params.put('skip', paging.skip)
            if paging.take is not None:
                params.put('take', paging.take)

        return params