Identify and explain the differences between the integration patch and the application modeling rules with the goal of completing the task.

<task>

Update PIP packages (MOM, arxml parser, others?) to support the updated modelling rules in the feature description.

Support from Iberia/tooling team is needed, to identify which modifications needs to be done
DoD

Investigate which packages need to be modified ( support from iberia/tooling might be needed)
Implement modifications
Acc

PR reviewed by iberia team

Feature
---
The SDG Requirement - WindChill ID 7436226 stablish that "ImplementationDataTypes shall not use DATA_REFERENCE as their CATEGORY."

Currently Customer Project SV62 and all other variants of HCP2.ME projects are using Data reference category

The SDG requirement - WindChill ID 7436064  is also impacted, since "void" base type may be used for the DATA_REFERENCE implementation types (it is used as such in HCP2ME model)

  

For SV62 project, there is a workaround in the first integration cycle with MotionWise 2.0 - It was added a fix  in a model touch up script that modifies the input ARXML files to comply with MotionWise modeling rules.

Benefit is that by removing this modeling rule (specification [constr_1006]) there wouldn't be restriction on customer projects to use AUTOSAR

 

Description
After removing this modeling rule from SDG and SDV, COM-BUF service will use the implementation of data reference category for Implementation datatype

Acceptance Criteria
Given the SDG Requirement - WindChill ID 7436226 and WindChill ID 7436064 

When modeling rule is removed from SDG and SDV

Then no error is reported in SDV violation report

Then COM-BUF service will handle the implementation of data reference category for Implementation datatype

Then all test cases will  pass successfully

 

Given the SDG Requirement - WindChill ID 7436226 and WindChill ID 7436064 

When modeling rule is removed from SDG and SDV

Then no error is reported in SDV violation report

Then COM_RTE service will handle the implementation of data reference category for Implementation datatype

Then Contract Headers will provide new data reference for implementation datatype

Then all test cases will  be executed and pass successfully

 

Meeting minutes with HCP2.mej people (Dejan Dekanovic and others)
Hi Everyone!
I forgot to send out the meeting minutes from yesterday's discussion. Basically the outcome was:
 Capability SPSTMW-810 was modified to add Windchill ID 7436064 as an impacted requirement. This modelling rule is also a blocker to DATA_REFERENCE as category for implementation data types.
Both requirements 7436226 and 7436064 shall be modified so that DATA_REFERENCE category (and void base type) is supported under certain restrictions - it shall be used only for client-server operations, for which "is service" is true
</task>

<patch>
# -*- coding: UTF-8 -*-
"""
Copyright (C) 2021 TTTech Computertechnik AG. All rights reserved
Schoenbrunnerstrasse 7, A--1040 Wien, Austria. <PRESIDIO_ANONYMIZED_EMAIL_ADDRESS>

Name
   touch_component_types.py

Purpose
   Rules for modifying the ComponentTypes.

Author
   Milos Mozetic     <<PRESIDIO_ANONYMIZED_EMAIL_ADDRESS>>

Revision Dates
    19-Oct-2021 Creation
"""

from logging_error_reporting import get_logger
from autosar_library.autosar_generic import (
    create_constant_for_data_type,
    create_init_value_to_data_element_path_dictionary,
    create_variable_access,
    get_first_periodic_runnable,
)
from autosar_objects.arxml_constants import AutosarConstants as AC
from autosar_objects.autosar_element import AutosarElement, AutosarReference
from autosar_objects.constant import Constant
from autosar_objects.component_behavior.internal_behavior import PortAPIOption
from autosar_objects.component_behavior.runnable_entity import (
    ServerCallPoint,
    AsynchronousServerCallResultPoint,
)
from autosar_objects.data_types.impl_data_type import ImplementationType
from autosar_objects.ecu_composition import ECUCompositionType, AssemblyConnector
from autosar_objects.port.port_interface import PortInterface
from autosar_objects.port.port_prototype import CommunicationSpec, PortPrototype
from autosar_objects.software_component import ComponentType
from touch_up_application.utilities.constants import XmlConstants
from touch_up_application.utilities.touch_rule import TouchRule
from touch_up_application.utilities.xml_parse_utilities import (
    QueuedReceiverCommSpec,
    QueuedSenderCommSpec,
    NonQueuedReceiverCommSpec,
    NonQueuedSenderCommSpec,
)
from tttech_library.tttech_generic import (
    is_middleware,
    determine_middleware_ports_and_names,
    find_all_mw_ports,
)
from tttech_library.tttech_cleaner import delete_ct_and_dependencies
from contract_header_patch_application.utilities.touch_utilities import (
    TouchUtilities
)

LOGGER = get_logger(__name__)


class TouchNewPortsOnComponentTypes(TouchRule):
    """
    This rule is used to add new Ports and Connections between ports based
    on specified list of Port Interfaces and Component Types.
    """

    class PortPrototypeConfiguration(object):
        """
        This inner class is used to store all configuration properties
        needed for Port Prototype creation. It contains all common configuration
        for one Port Prototype creation.

        :ivar ComponentType component_type: Instance of Component Type
            which shall be used to add new Port Prototype on it.
        :ivar PortInterface port_interface: Instance of Port Interface which
            shall be used to create new Port Prototype.
        :ivar str port_prototype_name: Desired name of Port Prototype, if None
            is passed, default one is created by replacing Pi with Pp.
        :ivar object port_specification: Class which contains
            parsed data from SENDER-RECEIVER-CONNECTION or
            CLIENT-SERVER-CONNECTION XML node.
        :ivar str interface_type: Type of interface, from PortPrototype class.
        :ivar str port_direction: Direction of port, from PortPrototype class.
        """

        def __init__(
            self,
            component_type,
            port_interface,
            port_prototype_name,
            port_specification,
            interface_type,
            port_direction,
        ):
            self.component_type = component_type
            self.port_interface = port_interface
            if port_prototype_name:
                self.port_prototype_name = port_prototype_name
            else:
                self.port_prototype_name = port_interface.name.replace("i", "p", 1)
            self.port_specification = port_specification
            self.interface_type = interface_type
            self.port_direction = port_direction

    def touch(self, mfwk_adapter):
        """
        Method that creates new connections between new ports on Component
        Types.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of the Modeling
            Framework adapter.
        :return: /
        """
        if self.configuration is not None and (
            self.configuration[XmlConstants.SENDER_RECEIVER_CONNECTION]
            or self.configuration[XmlConstants.CLIENT_SERVER_CONNECTION]
        ):
            mfwk_adapter.get_all(ComponentType)
            mfwk_adapter.get_all(PortInterface)
            mfwk_adapter.get_all(ImplementationType)
            mfwk_adapter.get_all(ECUCompositionType)
            mfwk_adapter.get_all(Constant)

            for sender_receiver_connection in self.configuration[
                XmlConstants.SENDER_RECEIVER_CONNECTION
            ]:
                self.create_sender_receiver_connection(
                    mfwk_adapter=mfwk_adapter,
                    sender_receiver_connection=sender_receiver_connection,
                )

            for client_server_connection in self.configuration[
                XmlConstants.CLIENT_SERVER_CONNECTION
            ]:
                self.create_client_server_connection(
                    mfwk_adapter=mfwk_adapter,
                    client_server_connection=client_server_connection,
                )
        else:
            LOGGER.info(
                "%s - Cannot be executed, because it requires the connections "
                "to create to be defined",
                TouchNewPortsOnComponentTypes.__name__,
            )

    def extract_config_rule(self, configuration_adapter, configuration_bundle):
        """
        Method for setting up :class:`TouchNewPortsOnComponentTypes`
        rule's configuration parameters.

        :param TouchRulesConfigurationAdapter configuration_adapter: Adapter
            for parsing the configuration file and extracting configuration parameters
            for the specific rule.
        :param object configuration_bundle: The part of the configuration that is
            specific for the rule.
        :return: /
        """
        self.configuration = (
            configuration_adapter.extract_touch_new_ports_on_component_types(
                configuration_bundle
            )
        )

    def create_sender_receiver_connection(
        self, mfwk_adapter, sender_receiver_connection
    ):
        """
        This method is used to create connection between Sender Port and
        Receiver Port, based on configuration in sender_receiver_connection.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter
            which contains loaded ARXML files.
        :param SenderReceiverConnection sender_receiver_connection: Instance
            of SenderReceiverConnection which contains all needed
            properties.
        :return: /
        """

        LOGGER.info(
            "Creating connection between sender %s and recevier %s via port %s.",
            sender_receiver_connection.sender_port.parent_swc_name,
            sender_receiver_connection.receiver_port.parent_swc_name,
            sender_receiver_connection.port_interface,
        )

        port_interface = mfwk_adapter.get_by_name(
            class_=PortInterface, name=sender_receiver_connection.port_interface
        )

        if port_interface is None:
            LOGGER.error(
                "Desired Port Interface %s does not exist in loaded "
                "ARXML files. Connection will not be created.",
                sender_receiver_connection.port_interface,
            )
            return

        sender_component_type = mfwk_adapter.get_by_name(
            class_=ComponentType,
            name=sender_receiver_connection.sender_port.parent_swc_name,
        )

        if sender_component_type is None:
            LOGGER.error(
                "Component Type with name %s does not exist in "
                "loaded ARXML files. Connection will not be created.",
                sender_receiver_connection.sender_port.parent_swc_name,
            )
            return

        receiver_component_type = mfwk_adapter.get_by_name(
            class_=ComponentType,
            name=sender_receiver_connection.receiver_port.parent_swc_name,
        )

        if receiver_component_type is None:
            LOGGER.error(
                "Component Type with name %s does not exist in "
                "loaded ARXML files. Connection will not be created.",
                sender_receiver_connection.receiver_port.parent_swc_name,
            )
            return

        sender_port_prototype = None
        for port in sender_component_type.ports:
            if port.port_interface.path == port_interface.ar_path:
                sender_port_prototype = port
                break

        receiver_port_prototype = None
        for port in receiver_component_type.ports:
            if port.port_interface.path == port_interface.ar_path:
                receiver_port_prototype = port
                break

        if sender_port_prototype and receiver_port_prototype:
            LOGGER.warning(
                "Ports %s and %s exist on desired Component Types. "
                "New connection will not be created.",
                sender_port_prototype.name,
                receiver_port_prototype.name,
            )
            return
        elif sender_port_prototype:
            LOGGER.info(
                "Existing initial values will be reused for R port from P port "
                "%s on %s",
                sender_port_prototype.name,
                sender_port_prototype.parent.name,
            )
            existing_init_values = create_init_value_to_data_element_path_dictionary(
                sender_port_prototype
            )
        elif receiver_port_prototype:
            LOGGER.info(
                "Existing initial values will be reused for P port from R port "
                "%s on %s",
                receiver_port_prototype.name,
                receiver_port_prototype.parent.name,
            )
            existing_init_values = create_init_value_to_data_element_path_dictionary(
                receiver_port_prototype
            )
        else:
            existing_init_values = None

        if sender_port_prototype is None:
            # Create sender Port Prototype on sender Component Type
            sender_port_prototype = self.create_port_prototype(
                mfwk_adapter=mfwk_adapter,
                port_prototype_configuration=self.PortPrototypeConfiguration(
                    component_type=sender_component_type,
                    port_interface=port_interface,
                    port_prototype_name=sender_receiver_connection.port_prototype,
                    port_specification=sender_receiver_connection.sender_port,
                    interface_type=PortPrototype.__SENDER_RECEIVER__,
                    port_direction=PortPrototype.__PRODUCER__,
                ),
                existing_init_values=existing_init_values,
            )
            # Add Variable Access
            self.create_variable_accesses_from_configuration(
                mfwk_adapter=mfwk_adapter,
                port_interface=port_interface,
                port_prototype=sender_port_prototype,
                runnables=sender_component_type.internal_behavior.runnables,
                variable_access_config=sender_receiver_connection.sender_port.variable_access,
            )
            # Add Port API Option
            self.create_port_api_option_from_configuration(
                port_prototype=sender_port_prototype,
                port_api_option_config=sender_receiver_connection.port_api_option,
            )

        if receiver_port_prototype is None:
            # Create receiver Port Prototype on receiver Component Type
            receiver_port_prototype = self.create_port_prototype(
                mfwk_adapter=mfwk_adapter,
                port_prototype_configuration=self.PortPrototypeConfiguration(
                    component_type=receiver_component_type,
                    port_interface=port_interface,
                    port_prototype_name=sender_receiver_connection.port_prototype,
                    port_specification=sender_receiver_connection.receiver_port,
                    interface_type=PortPrototype.__SENDER_RECEIVER__,
                    port_direction=PortPrototype.__RECEIVER__,
                ),
                existing_init_values=existing_init_values,
            )
            # Add Variable Access
            self.create_variable_accesses_from_configuration(
                mfwk_adapter=mfwk_adapter,
                port_interface=port_interface,
                port_prototype=receiver_port_prototype,
                runnables=receiver_component_type.internal_behavior.runnables,
                variable_access_config=sender_receiver_connection.receiver_port.variable_access,
            )
            # Add Port API Option
            self.create_port_api_option_from_configuration(
                port_prototype=receiver_port_prototype,
                port_api_option_config=sender_receiver_connection.port_api_option,
            )

        # Add ports to Middleware
        ct_cd_middleware = None
        for component_type in mfwk_adapter.get_all(ComponentType):
            if (
                is_middleware(component_type)
                and component_type.origin_hosts == sender_component_type.origin_hosts
            ):
                ct_cd_middleware = component_type

        (
            middleware_sender_port,
            middleware_sender_name,
            middleware_receiver_port,
            middleware_receiver_name,
        ) = determine_middleware_ports_and_names(
            ct_cd_middleware=ct_cd_middleware,
            port_name=sender_receiver_connection.port_prototype
            if sender_receiver_connection.port_prototype is not None
            else port_interface.name.replace("i", "p", 1),
        )

        if middleware_sender_port is None:
            # Create sender Port Prototype on Middleware
            middleware_sender_port = self.create_port_prototype(
                mfwk_adapter=mfwk_adapter,
                port_prototype_configuration=self.PortPrototypeConfiguration(
                    component_type=ct_cd_middleware,
                    port_interface=port_interface,
                    port_prototype_name=middleware_sender_name,
                    port_specification=sender_receiver_connection.sender_port,
                    interface_type=PortPrototype.__SENDER_RECEIVER__,
                    port_direction=PortPrototype.__PRODUCER__,
                ),
                existing_init_values=existing_init_values,
            )
            # Add Variable Access
            self.create_variable_accesses_from_configuration(
                mfwk_adapter=mfwk_adapter,
                port_interface=port_interface,
                port_prototype=middleware_sender_port,
                runnables=ct_cd_middleware.internal_behavior.runnables,
                variable_access_config=sender_receiver_connection.sender_port.variable_access,
            )
            # Add Port API Option
            self.create_port_api_option_from_configuration(
                port_prototype=middleware_sender_port,
                port_api_option_config=sender_receiver_connection.port_api_option,
            )

        if middleware_receiver_port is None:
            # Create receiver Port Prototype on Middleware
            middleware_receiver_port = self.create_port_prototype(
                mfwk_adapter=mfwk_adapter,
                port_prototype_configuration=self.PortPrototypeConfiguration(
                    component_type=ct_cd_middleware,
                    port_interface=port_interface,
                    port_prototype_name=middleware_receiver_name,
                    port_specification=sender_receiver_connection.receiver_port,
                    interface_type=PortPrototype.__SENDER_RECEIVER__,
                    port_direction=PortPrototype.__RECEIVER__,
                ),
                existing_init_values=existing_init_values,
            )
            # Add Variable Access
            self.create_variable_accesses_from_configuration(
                mfwk_adapter=mfwk_adapter,
                port_interface=port_interface,
                port_prototype=middleware_receiver_port,
                runnables=ct_cd_middleware.internal_behavior.runnables,
                variable_access_config=sender_receiver_connection.receiver_port.variable_access,
            )
            # Add Port API Option
            self.create_port_api_option_from_configuration(
                port_prototype=middleware_receiver_port,
                port_api_option_config=sender_receiver_connection.port_api_option,
            )

        mfwk_adapter.sync_element(receiver_component_type)
        mfwk_adapter.sync_element(sender_component_type)
        mfwk_adapter.sync_element(ct_cd_middleware)

        # Adding Assembly Connectors to ECU Composition.
        receiver_component_prototype = mfwk_adapter.used_by(receiver_component_type)[0]
        sender_component_prototype = mfwk_adapter.used_by(sender_component_type)[0]
        cp_cd_middleware = mfwk_adapter.used_by(ct_cd_middleware)[0]
        ecu_composition = cp_cd_middleware.parent

        ecu_composition.add_element(
            asr_element=AssemblyConnector(
                name="{}D{}D{}D{}".format(
                    sender_component_prototype.name,
                    sender_port_prototype.name,
                    cp_cd_middleware.name,
                    middleware_receiver_port.name,
                ),
                provider_port_ref=AutosarReference(
                    path=sender_port_prototype.ar_path, dest=AC.P_PORT_PROTOTYPE
                ),
                provider_component_ref=AutosarReference(
                    path=sender_component_prototype.ar_path,
                    dest=AC.SW_COMPONENT_PROTOTYPE,
                ),
                requester_port_ref=AutosarReference(
                    path=middleware_receiver_port.ar_path, dest=AC.R_PORT_PROTOTYPE
                ),
                requester_component_ref=AutosarReference(
                    path=cp_cd_middleware.ar_path, dest=AC.SW_COMPONENT_PROTOTYPE
                ),
            )
        )
        ecu_composition.add_element(
            asr_element=AssemblyConnector(
                name="{}D{}D{}D{}".format(
                    cp_cd_middleware.name,
                    middleware_sender_port.name,
                    receiver_component_prototype.name,
                    receiver_port_prototype.name,
                ),
                provider_port_ref=AutosarReference(
                    path=middleware_sender_port.ar_path, dest=AC.P_PORT_PROTOTYPE
                ),
                provider_component_ref=AutosarReference(
                    path=cp_cd_middleware.ar_path, dest=AC.SW_COMPONENT_PROTOTYPE
                ),
                requester_port_ref=AutosarReference(
                    path=receiver_port_prototype.ar_path, dest=AC.R_PORT_PROTOTYPE
                ),
                requester_component_ref=AutosarReference(
                    path=receiver_component_prototype.ar_path,
                    dest=AC.SW_COMPONENT_PROTOTYPE,
                ),
            )
        )
        mfwk_adapter.sync_element(ecu_composition)

    def create_port_prototype(
        self,
        mfwk_adapter,
        port_prototype_configuration,
        existing_init_values,
    ):
        """
        This method is used to create new Port Prototype on passed
        Component Type with specification parsed from Configuration XML node.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter
            which contains loaded ARXML files.
        :param self.PortPrototypeConfiguration port_prototype_configuration:
            Instance of PortPrototypeConfiguration which contains all needed
            properties for Port Prototype creation.
        :param dict existing_init_values: Dictionary of initial values with key
            of data element ar_path, and values in form of tuple, where first
            value is init_type and second one is init_value.
        :return: Instance of PortPrototype which is created.
        :rtype: PortPrototype
        """
        communication_specs = []
        communication_specs_config = (
            port_prototype_configuration.port_specification.communication_spec
        )
        for data_element in port_prototype_configuration.port_interface.members:
            communication_specs.append(
                self.create_comm_spec_from_configuration(
                    mfwk_adapter=mfwk_adapter,
                    data_element=data_element,
                    communication_specs_config=communication_specs_config,
                    existing_init_values=existing_init_values,
                )
            )

        port_prototype = PortPrototype(
            name=port_prototype_configuration.port_prototype_name,
            port_interface=AutosarReference(
                path=port_prototype_configuration.port_interface.ar_path,
                dest=AC.SENDER_RECEIVER_INTERFACE,
            ),
            interface_type=port_prototype_configuration.interface_type,
            direction=port_prototype_configuration.port_direction,
            communication_specs=communication_specs,
        )

        LOGGER.info(
            "Added %s port %s to component %s",
            port_prototype.direction,
            port_prototype.name,
            port_prototype_configuration.component_type.name,
        )
        port_prototype_configuration.component_type.add_element(port_prototype)

        return port_prototype

    def create_comm_spec_from_configuration(
        self,
        mfwk_adapter,
        data_element,
        communication_specs_config,
        existing_init_values,
    ):
        """
        This method is used to create CommunicationSpec instance from passed
        configuration parsed from XML configuration file.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter which
            contains all loaded AUTOSAR objects needed to create CommunicationSpec.
        :param VariableDataPrototype data_element: Instance of VariableDataPrototype
            which represents data element for which CommunicationSpec shall be
            created.
        :param object communication_specs_config: Instance of appripriate
            Configuration that is parsed from XML configuration file.
        :param dict existing_init_values: Dictionary of initial values with key
            of data element ar_path, and values in form of tuple, where first
            value is init_type and second one is init_value.
        :return: Instance of CommunicationSpec object filled
        """
        data_type = mfwk_adapter.get_by_ar_path(
            ImplementationType, data_element.type_ref.path
        )

        if existing_init_values and data_element.ar_path in existing_init_values:
            LOGGER.debug("Using existing initial value for %s", data_element.ar_path)
            init_value = existing_init_values[data_element.ar_path]
        else:
            LOGGER.debug("Creating new initial value for %s", data_element.ar_path)
            constant_reference = create_constant_for_data_type(
                constant_name=AC.CONSTANT_PREFIX
                + data_type.name[len(AC.DATA_TYPE_PREFIX) :],
                implementation_data_type=data_type,
                mfwk_adapter=mfwk_adapter,
            )
            init_value = Constant.Field(
                category=AC.CONSTANT_REFERENCE,
                constant_ref=constant_reference,
            )

        if isinstance(communication_specs_config, QueuedSenderCommSpec):
            communication_spec = CommunicationSpec(
                kind=communication_specs_config.kind,
                data_element_reference=data_element.ar_path,
                init_value=init_value,
                handle_out_of_range=communication_specs_config.handle_out_of_range,
                transmission_acknowledge=communication_specs_config.transmission_acknowledge,
                uses_end_to_end_protection=communication_specs_config.uses_end_to_end_protection,
            )
        elif isinstance(communication_specs_config, NonQueuedSenderCommSpec):
            communication_spec = CommunicationSpec(
                kind=communication_specs_config.kind,
                data_element_reference=data_element.ar_path,
                init_value=init_value,
                handle_out_of_range=communication_specs_config.handle_out_of_range,
                transmission_acknowledge=communication_specs_config.transmission_acknowledge,
                uses_end_to_end_protection=communication_specs_config.uses_end_to_end_protection,
            )
        elif isinstance(communication_specs_config, QueuedReceiverCommSpec):
            communication_spec = CommunicationSpec(
                kind=communication_specs_config.kind,
                data_element_reference=data_element.ar_path,
                init_value=init_value,
                handle_out_of_range=communication_specs_config.handle_out_of_range,
                uses_end_to_end_protection=communication_specs_config.uses_end_to_end_protection,
                queue_length=communication_specs_config.queue_length,
            )
        elif isinstance(communication_specs_config, NonQueuedReceiverCommSpec):
            communication_spec = CommunicationSpec(
                kind=communication_specs_config.kind,
                data_element_reference=data_element.ar_path,
                init_value=init_value,
                handle_out_of_range=communication_specs_config.handle_out_of_range,
                uses_end_to_end_protection=communication_specs_config.uses_end_to_end_protection,
                alive_timeout=communication_specs_config.alive_timeout,
                enable_update=communication_specs_config.enable_update,
                data_filter_type=communication_specs_config.data_filter_type,
                handle_never_received=communication_specs_config.handle_never_received,
                handle_timeout_type=communication_specs_config.handle_timeout_type,
            )
        else:
            communication_spec = None

        return communication_spec

    def create_variable_accesses_from_configuration(
        self,
        mfwk_adapter,
        port_interface,
        port_prototype,
        runnables,
        variable_access_config,
    ):
        """
        This method is used to create VariableAccess instances from passed
        configuration parsed from XML configuration file.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter which
            contains all loaded AUTOSAR objects needed to create VariableAccess
            instances.
        :param PortInterface port_interface: Instance of PortInterface which
            contains all Data Elements for which Variable Access shall be added.
        :param PortPrototype port_prototype: Instance of PortPrototype which is
            used to create Variable Access.
        :param list runnables: List of runnables used to find first periodic
            Runnable or desired one from configuration.
        :param object variable_access_config: Instance of appripriate
            Configuration that is parsed from XML configuration file.
        """
        runnable = None
        if variable_access_config.runnable:
            runnable = AutosarElement.find_element_by_key(
                value=variable_access_config.runnable,
                element_list=runnables,
                key=AC.NAME,
            )

        if is_middleware(port_prototype.parent):
            access = variable_access_config.middleware_kind
        else:
            access = variable_access_config.kind

        for data_element in port_interface.members:
            create_variable_access(
                adapter_host=mfwk_adapter,
                port_prototype=port_prototype,
                data_element=data_element,
                access=access,
                runnable=runnable,
            )

    def create_port_api_option_from_configuration(
        self, port_prototype, port_api_option_config
    ):
        """
        This method is used to create PortAPIOption for passed instance of Port
        Prototype from passed configuration parsed from XML configuration file.

        :param PortPrototype port_prototype: Instance of PortPrototype for which
            PortAPIOption shall be added.
        :param object port_api_option_config: Instance of appripriate
            Configuration that is parsed from XML configuration file.
        """
        # Port API Option does not exist
        if port_api_option_config is None:
            return

        if port_prototype.parent is None:
            LOGGER.error(
                "Please add Port Prototype %s to Component Type in "
                "order to add Port API Option.",
                port_prototype.name,
            )
            return

        if port_prototype.direction == PortPrototype.__RECEIVER__:
            port_ref_dest = PortAPIOption.__R_PORT_PROTOTYPE__
        else:
            port_ref_dest = PortAPIOption.__P_PORT_PROTOTYPE__

        port_api_option = PortAPIOption(
            enable_take_address=port_api_option_config.enable_take_address,
            packing_byte_order=port_api_option_config.error_handling,
            indirect_api=port_api_option_config.indirect_api,
            port_ref=port_prototype.ar_path,
            port_ref_dest=port_ref_dest,
        )

        port_prototype.parent.internal_behavior.add_element(port_api_option)

    def create_client_server_connection(self, mfwk_adapter, client_server_connection):
        """
        This method is used to create connection between Client Port and
        Server Port, based on configuration in client_server_connection.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter
            which contains loaded ARXML files.
        :param ClientServerConnection client_server_connection: Instance
            of ClientServerConnection which contains all needed
            properties.
        :return: /
        """

        LOGGER.info(
            "Creating connection between server %s and client %s via port %s",
            client_server_connection.server_port,
            client_server_connection.client_port.parent_swc_name,
            client_server_connection.port_interface,
        )

        port_interface = mfwk_adapter.get_by_name(
            class_=PortInterface, name=client_server_connection.port_interface
        )

        if port_interface is None:
            LOGGER.error(
                "Desired Port Interface %s does not exist in loaded "
                "ARXML files. Connection will not be created.",
                client_server_connection.port_interface,
            )
            return

        server_component_type = mfwk_adapter.get_by_name(
            class_=ComponentType,
            name=client_server_connection.server_port,
        )

        if server_component_type is None:
            LOGGER.error(
                "Server Component Type with name %s does not exist in "
                "loaded ARXML files. Connection will not be created.",
                client_server_connection.server_port,
            )
            return

        client_component_type = mfwk_adapter.get_by_name(
            class_=ComponentType,
            name=client_server_connection.client_port.parent_swc_name,
        )

        if client_component_type is None:
            LOGGER.error(
                "Client Component Type with name %s does not exist in "
                "loaded ARXML files. Connection will not be created.",
                client_server_connection.client_port.parent_swc_name,
            )
            return

        server_port_prototype = None
        for port in server_component_type.ports:
            if port.port_interface.path == port_interface.ar_path:
                server_port_prototype = port
                break

        client_port_prototype = None
        for port in client_component_type.ports:
            if port.port_interface.path == port_interface.ar_path:
                client_port_prototype = port
                break

        if server_port_prototype is None:
            LOGGER.error(
                "Server port prototype of port interface %s does not exist in "
                "%s server component type. Connection will not be created.",
                port_interface.name,
                server_component_type.name,
            )
            return

        if client_port_prototype is None:
            prototype_name = ""
            if client_server_connection.port_prototype:
                prototype_name = client_server_connection.port_prototype
            elif port_interface.name.startswith("Pi"):
                prototype_name = port_interface.name.replace("Pi", "Pp")
            else:
                prototype_name = "{}{}".format("Pp", port_interface.name)

            port_config = self.PortPrototypeConfiguration(
                component_type=client_component_type,
                port_interface=port_interface,
                port_prototype_name=prototype_name,
                port_specification=client_server_connection.client_port,
                interface_type=PortPrototype.__CLIENT_SERVER__,
                port_direction=PortPrototype.__RECEIVER__,
            )
            # Create client port prototype.
            client_port_prototype = self.create_client_port_prototype(
                mfwk_adapter=mfwk_adapter,
                port_config=port_config,
            )
            # Add server call points for the new client port prototype.
            self.add_server_call_points_to_runnable(
                mfwk_adapter=mfwk_adapter,
                port_prototype=client_port_prototype,
                port_config=port_config,
            )
            # Add port API option for the new client port prototype.
            self.create_port_api_option_from_configuration(
                port_prototype=client_port_prototype,
                port_api_option_config=client_server_connection.port_api_option,
            )
            mfwk_adapter.sync_element(asr_element=client_component_type)
        else:
            LOGGER.info(
                "Client port prototype %s, already exist in the client "
                "component type %s, so it won't be created.",
                client_port_prototype.name,
                client_component_type.name,
            )
        # Create Assembly connector.
        self.create_connector(
            provider_port=server_port_prototype,
            requester_port=client_port_prototype,
            mfwk_adapter=mfwk_adapter,
        )

    def create_client_port_prototype(
        self,
        mfwk_adapter,
        port_config,
    ):
        """
        This method is used to create new Client Port Prototype on passed
        Component Type with specification parsed from CLIENT-SERVER-CONNECTION
        XML node.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter
            which contains loaded ARXML files.
        :param self.PortPrototypeConfiguration port_config: Instance
            of PortPrototypeConfiguration which contains all needed properties
            for Port Prototype creation.
        :return: Instance of the created client ::class:`PortPrototype`
        :rtype: PortPrototype
        """
        # Create the prototype with communication specification elements for each
        # client/server operation.
        port_prototype = PortPrototype(
            name=port_config.port_prototype_name,
            port_interface=AutosarReference(
                path=port_config.port_interface.ar_path,
                dest=AC.CLIENT_SERVER_INTERFACE,
            ),
            interface_type=port_config.interface_type,
            direction=port_config.port_direction,
            communication_specs=[
                CommunicationSpec(
                    kind=CommunicationSpec.__CLIENT_SPEC__,
                    operation_reference=client_server_operation.ar_path,
                )
                for client_server_operation in port_config.port_interface.members
            ],
        )
        mfwk_adapter.add_element(
            asr_element=port_prototype, parent=port_config.component_type
        )
        return port_prototype

    def add_server_call_points_to_runnable(
        self, mfwk_adapter, port_prototype, port_config
    ):
        """
        This method is used to create a server call point for each client/server
        operation of the port prototype and add it to the runnable of the component type
        where the port prototype is instantiated. If the runnable name is not explicitly
        specified in the port configuration, then server call points are added to the
        first periodic runnable of the component type.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter
            which contains loaded ARXML files.
        :param PortPrototype port_prototype: Instance of the client port prototype whose
            client/server operations are used to create server call points.
        :param self.PortPrototypeConfiguration port_config: Instance
            of PortPrototypeConfiguration which contains all needed properties
            for Port Prototype creation.
        :return: /
        """
        # Create the server call points in runnable with the specified access type.
        server_call_point_config = port_config.port_specification.server_call_point
        if server_call_point_config.runnable:
            runnable = AutosarElement.find_element_by_key(
                element_list=port_config.component_type.internal_behavior.runnables,
                value=server_call_point_config.runnable,
                key=AC.NAME,
            )
            if runnable is None:
                LOGGER.error(
                    "Runnable %s does not exist in "
                    "%s client component type. "
                    "Connection will not be created.",
                    server_call_point_config.runnable,
                    port_config.component_type.name,
                )
                return
        else:
            runnable = get_first_periodic_runnable(
                component_type=port_config.component_type
            )
            if runnable is None:
                LOGGER.error(
                    "Could not find periodic runnable in "
                    "%s client component type. "
                    "Connection will not be created.",
                    port_config.component_type.name,
                )
                return

        new_server_call_points = [
            self.create_server_call_point(
                server_call_point_config=server_call_point_config,
                port_prototype=port_prototype,
                client_server_operation=client_server_operation,
            )
            for client_server_operation in port_config.port_interface.members
        ]
        LOGGER.info(
            "Adding server call points to the runnable %s.",
            runnable.name,
        )
        runnable.server_call_points.extend(new_server_call_points)
        if server_call_point_config.kind == "ASYNCHRONOUS":
            # Add result points in case of async server call point.
            new_result_points = [
                AsynchronousServerCallResultPoint(
                    name="ASCRP_{}_{}".format(runnable.name, scp.name),
                    asynchronous_server_call_point_ref=scp.operation.cs_operation_ref.path,
                )
                for scp in new_server_call_points
            ]
            runnable.asynchronous_server_call_result_points.extend(new_result_points)

        mfwk_adapter.sync_element(asr_element=port_config.component_type)

    @staticmethod
    def create_server_call_point(
        server_call_point_config, port_prototype, client_server_operation
    ):
        """
        Helper method used to create the server call point based on the given
        configuration.

        :param xml_parse_utilities.ServerCallPoint server_call_point_config:
        :param PortPrototype port_prototype:
        :param ClientServerOperation client_server_operation:
        :return: Created instance of the ::class:`ServerCallPoint`
        :rtype: ServerCallPoint
        """
        point_kind = (
            ServerCallPoint.__SYNC_TYPE__
            if server_call_point_config.kind == "SYNCHRONOUS"
            else ServerCallPoint.__ASYNC_TYPE__
        )
        return ServerCallPoint(
            name="{}_{}_{}".format(
                "SC" if point_kind == ServerCallPoint.__SYNC_TYPE__ else "AC",
                port_prototype.name,
                client_server_operation.name,
            ),
            variant=point_kind,
            operation=ServerCallPoint.Operation(
                port_prototype_ref=ServerCallPoint.Operation.PortPrototypeRef(
                    variant=ServerCallPoint.Operation.__PORT_RECEIVER__,
                    path=port_prototype.ar_path,
                    parser_element=None,
                ),
                cs_operation_ref=ServerCallPoint.Operation.CSOperationRef(
                    variant=ServerCallPoint.Operation.__OPERATION_REQUIRED__,
                    path=client_server_operation.ar_path,
                    parser_element=None,
                ),
            ),
            timeout=server_call_point_config.timeout
            if server_call_point_config.timeout
            else 0,
        )

    def create_connector(self, provider_port, requester_port, mfwk_adapter):
        """
        This method is used to create assembly connector between two ports on the
        components that belong to the root host composition type.

        :param PortPrototype provider_port: /
        :param PortPrototype requester_port: /
        :param ArxmlAsrAdapter mfwk_adapter: /
        :return: Instance of the ::class:`AssemblyConnector`
        :rtype: AssemblyConnector
        """
        # Find the composition where the components are instantiated to created the
        # connection between them.
        req_usage = mfwk_adapter.used_by(requester_port.parent)
        prov_usage = mfwk_adapter.used_by(provider_port.parent)
        requester_component_prototype = req_usage[0] if req_usage else None
        provider_component_prototype = prov_usage[0] if prov_usage else None

        if (
            requester_component_prototype is None
            or provider_component_prototype is None
        ):
            LOGGER.error(
                "Could not create the connection between server and client "
                "components, because their prototypes are not found"
            )
            return

        if requester_component_prototype.parent != provider_component_prototype.parent:
            LOGGER.error(
                "Could not create the connection between server and client "
                "components, because they are not part of the same root host "
                "composition type"
            )
            return

        root_composition = provider_component_prototype.parent

        connector = AssemblyConnector(
            name="{}D{}D{}D{}".format(
                provider_component_prototype.name,
                provider_port.name,
                requester_component_prototype.name,
                requester_port.name,
            ),
            provider_component_ref=AutosarReference(
                path=provider_component_prototype.ar_path,
                dest=AC.SW_COMPONENT_PROTOTYPE,
            ),
            provider_port_ref=AutosarReference(
                path=provider_port.ar_path, dest=AC.P_PORT_PROTOTYPE
            ),
            requester_component_ref=AutosarReference(
                path=requester_component_prototype.ar_path,
                dest=AC.SW_COMPONENT_PROTOTYPE,
            ),
            requester_port_ref=AutosarReference(
                path=requester_port.ar_path, dest=AC.R_PORT_PROTOTYPE
            ),
        )
        mfwk_adapter.add_element(
            asr_element=connector, parent=root_composition, overwrite=False
        )


class TouchRemoveComponentTypes(TouchRule):
    """
    This class is used to implement the rule for removing software component types from
    the model.
    """

    def touch(self, mfwk_adapter):
        """
        The method that executes modeling actions for removing software component type,
        its prototype and connections from the model. The connections through the
        Middleware component are also deleted.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of the Modeling Framework adapter.
        :return: /
        """
        if self.configuration is None:
            LOGGER.info(
                "%s - Cannot be executed, because it requires "
                "the component types to remove "
                "to be specified.",
                TouchRemoveComponentTypes.__name__,
            )
            return

        for component_config in self.configuration:
            component_type = mfwk_adapter.get_by_name(
                class_=ComponentType, name=component_config.type_name
            )
            if component_type is None:
                LOGGER.info(
                    "%s - Component type %s cannot be found in the model.",
                    TouchRemoveComponentTypes.__name__,
                    component_config.type_name,
                )
                continue
            delete_ct_and_dependencies(
                ct_to_delete=component_type,
                all_mw_ports=find_all_mw_ports(
                    component_types=mfwk_adapter.get_all(ComponentType)
                ),
                adapter=mfwk_adapter,
            )

    def extract_config_rule(self, configuration_adapter, configuration_bundle):
        """
        Method for setting up :class:`TouchRemoveComponentTypes`
        rule's configuration parameters.

        :param TouchRulesConfigurationAdapter configuration_adapter: Adapter for
            parsing the configuration file and extracting configuration parameters for
            the specific rule.
        :param object configuration_bundle: The part of the configuration that is
            specific for the rule.
        :return: /
        """
        self.configuration = configuration_adapter.extract_touch_remove_component_types(
            configuration_bundle
        )


class TouchRemoveRunnables(TouchRule):
    """
    This class is used to implement the rule for removing defined Runnable entities
    from the software component type.
    """

    def touch(self, mfwk_adapter, repository_paths, component_type_dict):
        """
        The method that executes modeling actions for removing runnable
        entities from the software component types, and events that are
        used to trigger them.

        :param ArxmlAsrAdapter mfwk_adapter: 
            Instance of the Modeling Framework adapter.
        :param list(str) repository_paths: 
            List of paths to repositories 1700 and 1900.
        :param dict(list) component_type_dict: 
            Displacement component types per host.
        :return: /
        """
        if self.configuration is None:
            LOGGER.info(
                "%s - Cannot be executed, because it requires "
                "the component types with runnables to remove "
                "to be specified.",
                TouchRemoveRunnables.__name__,
            )
            return

        for component_config in self.configuration:
            component_type = mfwk_adapter.get_by_name(
                class_=ComponentType, name=component_config.type_name
            )
            if component_type is None:
                LOGGER.info(
                    "%s - Component type %s cannot be found in the model.",
                    TouchRemoveRunnables.__name__,
                    component_config.type_name,
                )
                continue
            for runnable_name in component_config.runnables:
                runnable = AutosarElement.find_element_by_key(
                    value=runnable_name,
                    element_list=component_type.internal_behavior.runnables,
                    key=AC.NAME,
                )
                if runnable is None:
                    LOGGER.info(
                        "%s - Runnable %s is not present in the component type %s.",
                        TouchRemoveRunnables.__name__,
                        runnable_name,
                        component_type.name,
                    )
                    continue

                host_name = TouchUtilities.get_host_of_ct(component_type.name,
                                                          component_type_dict)

                TouchUtilities.copy_server_rnbl(
                    repository_paths=repository_paths,
                    host_name=host_name,
                    runnable=runnable,
                    component_type=component_type)


    def extract_config_rule(self, configuration_adapter, configuration_bundle):
        """
        Method for setting up :class:`TouchRemoveRunnables`
        rule's configuration parameters.

        :param TouchRulesConfigurationAdapter configuration_adapter: Adapter for
            parsing the configuration file and extracting configuration parameters for
            the specific rule.
        :param object configuration_bundle: The part of the configuration that is
            specific for the rule.
        :return: /
        """
        self.configuration = configuration_adapter.extract_touch_remove_runnables(
            configuration_bundle
        )
                    
                    

</patch>

<rules>
# -*- coding: UTF-8 -*-
"""
Copyright (C) 2021 TTTech Computertechnik AG. All rights reserved
Schoenbrunnerstrasse 7, A--1040 Wien, Austria. <PRESIDIO_ANONYMIZED_EMAIL_ADDRESS>

Name
   touch_component_types.py

Purpose
   Rules for modifying the ComponentTypes.

Author
   Milos Mozetic     <<PRESIDIO_ANONYMIZED_EMAIL_ADDRESS>>

Revision Dates
    19-Oct-2021 Creation
"""

from logging_error_reporting import get_logger
from autosar_library.autosar_generic import (
    create_constant_for_data_type,
    create_init_value_to_data_element_path_dictionary,
    create_variable_access,
    get_first_periodic_runnable,
)
from autosar_objects.arxml_constants import AutosarConstants as AC
from autosar_objects.autosar_element import AutosarElement, AutosarReference
from autosar_objects.constant import Constant
from autosar_objects.component_behavior.internal_behavior import PortAPIOption
from autosar_objects.component_behavior.runnable_entity import (
    ServerCallPoint,
    AsynchronousServerCallResultPoint,
)
from autosar_objects.data_types.impl_data_type import ImplementationType
from autosar_objects.ecu_composition import ECUCompositionType, AssemblyConnector
from autosar_objects.port.port_interface import PortInterface
from autosar_objects.port.port_prototype import CommunicationSpec, PortPrototype
from autosar_objects.software_component import ComponentType
from touch_up_application.utilities.constants import XmlConstants
from touch_up_application.utilities.touch_rule import TouchRule
from touch_up_application.utilities.xml_parse_utilities import (
    QueuedReceiverCommSpec,
    QueuedSenderCommSpec,
    NonQueuedReceiverCommSpec,
    NonQueuedSenderCommSpec,
)
from tttech_library.tttech_generic import (
    is_middleware,
    determine_middleware_ports_and_names,
    find_all_mw_ports,
)
from tttech_library.tttech_cleaner import delete_ct_and_dependencies

LOGGER = get_logger(__name__)


class TouchNewPortsOnComponentTypes(TouchRule):
    """
    This rule is used to add new Ports and Connections between ports based
    on specified list of Port Interfaces and Component Types.
    """

    class PortPrototypeConfiguration(object):
        """
        This inner class is used to store all configuration properties
        needed for Port Prototype creation. It contains all common configuration
        for one Port Prototype creation.

        :ivar ComponentType component_type: Instance of Component Type
            which shall be used to add new Port Prototype on it.
        :ivar PortInterface port_interface: Instance of Port Interface which
            shall be used to create new Port Prototype.
        :ivar str port_prototype_name: Desired name of Port Prototype, if None
            is passed, default one is created by replacing Pi with Pp.
        :ivar object port_specification: Class which contains
            parsed data from SENDER-RECEIVER-CONNECTION or
            CLIENT-SERVER-CONNECTION XML node.
        :ivar str interface_type: Type of interface, from PortPrototype class.
        :ivar str port_direction: Direction of port, from PortPrototype class.
        """

        def __init__(
            self,
            component_type,
            port_interface,
            port_prototype_name,
            port_specification,
            interface_type,
            port_direction,
        ):
            self.component_type = component_type
            self.port_interface = port_interface
            if port_prototype_name:
                self.port_prototype_name = port_prototype_name
            else:
                self.port_prototype_name = port_interface.name.replace("i", "p", 1)
            self.port_specification = port_specification
            self.interface_type = interface_type
            self.port_direction = port_direction

    def touch(self, mfwk_adapter):
        """
        Method that creates new connections between new ports on Component
        Types.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of the Modeling
            Framework adapter.
        :return: /
        """
        if self.configuration is not None and (
            self.configuration[XmlConstants.SENDER_RECEIVER_CONNECTION]
            or self.configuration[XmlConstants.CLIENT_SERVER_CONNECTION]
        ):
            mfwk_adapter.get_all(ComponentType)
            mfwk_adapter.get_all(PortInterface)
            mfwk_adapter.get_all(ImplementationType)
            mfwk_adapter.get_all(ECUCompositionType)
            mfwk_adapter.get_all(Constant)

            for sender_receiver_connection in self.configuration[
                XmlConstants.SENDER_RECEIVER_CONNECTION
            ]:
                self.create_sender_receiver_connection(
                    mfwk_adapter=mfwk_adapter,
                    sender_receiver_connection=sender_receiver_connection,
                )

            for client_server_connection in self.configuration[
                XmlConstants.CLIENT_SERVER_CONNECTION
            ]:
                self.create_client_server_connection(
                    mfwk_adapter=mfwk_adapter,
                    client_server_connection=client_server_connection,
                )
        else:
            LOGGER.info(
                "%s - Cannot be executed, because it requires the connections "
                "to create to be defined",
                TouchNewPortsOnComponentTypes.__name__,
            )

    def extract_config_rule(self, configuration_adapter, configuration_bundle):
        """
        Method for setting up :class:`TouchNewPortsOnComponentTypes`
        rule's configuration parameters.

        :param TouchRulesConfigurationAdapter configuration_adapter: Adapter
            for parsing the configuration file and extracting configuration parameters
            for the specific rule.
        :param object configuration_bundle: The part of the configuration that is
            specific for the rule.
        :return: /
        """
        self.configuration = (
            configuration_adapter.extract_touch_new_ports_on_component_types(
                configuration_bundle
            )
        )

    def create_sender_receiver_connection(
        self, mfwk_adapter, sender_receiver_connection
    ):
        """
        This method is used to create connection between Sender Port and
        Receiver Port, based on configuration in sender_receiver_connection.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter
            which contains loaded ARXML files.
        :param SenderReceiverConnection sender_receiver_connection: Instance
            of SenderReceiverConnection which contains all needed
            properties.
        :return: /
        """

        LOGGER.info(
            "Creating connection between sender %s and recevier %s via port %s.",
            sender_receiver_connection.sender_port.parent_swc_name,
            sender_receiver_connection.receiver_port.parent_swc_name,
            sender_receiver_connection.port_interface,
        )

        port_interface = mfwk_adapter.get_by_name(
            class_=PortInterface, name=sender_receiver_connection.port_interface
        )

        if port_interface is None:
            LOGGER.error(
                "Desired Port Interface %s does not exist in loaded "
                "ARXML files. Connection will not be created.",
                sender_receiver_connection.port_interface,
            )
            return

        sender_component_type = mfwk_adapter.get_by_name(
            class_=ComponentType,
            name=sender_receiver_connection.sender_port.parent_swc_name,
        )

        if sender_component_type is None:
            LOGGER.error(
                "Component Type with name %s does not exist in "
                "loaded ARXML files. Connection will not be created.",
                sender_receiver_connection.sender_port.parent_swc_name,
            )
            return

        receiver_component_type = mfwk_adapter.get_by_name(
            class_=ComponentType,
            name=sender_receiver_connection.receiver_port.parent_swc_name,
        )

        if receiver_component_type is None:
            LOGGER.error(
                "Component Type with name %s does not exist in "
                "loaded ARXML files. Connection will not be created.",
                sender_receiver_connection.receiver_port.parent_swc_name,
            )
            return

        sender_port_prototype = None
        for port in sender_component_type.ports:
            if port.port_interface.path == port_interface.ar_path:
                sender_port_prototype = port
                break

        receiver_port_prototype = None
        for port in receiver_component_type.ports:
            if port.port_interface.path == port_interface.ar_path:
                receiver_port_prototype = port
                break

        if sender_port_prototype and receiver_port_prototype:
            LOGGER.warning(
                "Ports %s and %s exist on desired Component Types. "
                "New connection will not be created.",
                sender_port_prototype.name,
                receiver_port_prototype.name,
            )
            return
        elif sender_port_prototype:
            LOGGER.info(
                "Existing initial values will be reused for R port from P port "
                "%s on %s",
                sender_port_prototype.name,
                sender_port_prototype.parent.name,
            )
            existing_init_values = create_init_value_to_data_element_path_dictionary(
                sender_port_prototype
            )
        elif receiver_port_prototype:
            LOGGER.info(
                "Existing initial values will be reused for P port from R port "
                "%s on %s",
                receiver_port_prototype.name,
                receiver_port_prototype.parent.name,
            )
            existing_init_values = create_init_value_to_data_element_path_dictionary(
                receiver_port_prototype
            )
        else:
            existing_init_values = None

        if sender_port_prototype is None:
            # Create sender Port Prototype on sender Component Type
            sender_port_prototype = self.create_port_prototype(
                mfwk_adapter=mfwk_adapter,
                port_prototype_configuration=self.PortPrototypeConfiguration(
                    component_type=sender_component_type,
                    port_interface=port_interface,
                    port_prototype_name=sender_receiver_connection.port_prototype,
                    port_specification=sender_receiver_connection.sender_port,
                    interface_type=PortPrototype.__SENDER_RECEIVER__,
                    port_direction=PortPrototype.__PRODUCER__,
                ),
                existing_init_values=existing_init_values,
            )
            # Add Variable Access
            self.create_variable_accesses_from_configuration(
                mfwk_adapter=mfwk_adapter,
                port_interface=port_interface,
                port_prototype=sender_port_prototype,
                runnables=sender_component_type.internal_behavior.runnables,
                variable_access_config=sender_receiver_connection.sender_port.variable_access,
            )
            # Add Port API Option
            self.create_port_api_option_from_configuration(
                port_prototype=sender_port_prototype,
                port_api_option_config=sender_receiver_connection.port_api_option,
            )

        if receiver_port_prototype is None:
            # Create receiver Port Prototype on receiver Component Type
            receiver_port_prototype = self.create_port_prototype(
                mfwk_adapter=mfwk_adapter,
                port_prototype_configuration=self.PortPrototypeConfiguration(
                    component_type=receiver_component_type,
                    port_interface=port_interface,
                    port_prototype_name=sender_receiver_connection.port_prototype,
                    port_specification=sender_receiver_connection.receiver_port,
                    interface_type=PortPrototype.__SENDER_RECEIVER__,
                    port_direction=PortPrototype.__RECEIVER__,
                ),
                existing_init_values=existing_init_values,
            )
            # Add Variable Access
            self.create_variable_accesses_from_configuration(
                mfwk_adapter=mfwk_adapter,
                port_interface=port_interface,
                port_prototype=receiver_port_prototype,
                runnables=receiver_component_type.internal_behavior.runnables,
                variable_access_config=sender_receiver_connection.receiver_port.variable_access,
            )
            # Add Port API Option
            self.create_port_api_option_from_configuration(
                port_prototype=receiver_port_prototype,
                port_api_option_config=sender_receiver_connection.port_api_option,
            )

        # Add ports to Middleware
        ct_cd_middleware = None
        for component_type in mfwk_adapter.get_all(ComponentType):
            if (
                is_middleware(component_type)
                and component_type.origin_hosts == sender_component_type.origin_hosts
            ):
                ct_cd_middleware = component_type

        (
            middleware_sender_port,
            middleware_sender_name,
            middleware_receiver_port,
            middleware_receiver_name,
        ) = determine_middleware_ports_and_names(
            ct_cd_middleware=ct_cd_middleware,
            port_name=sender_receiver_connection.port_prototype
            if sender_receiver_connection.port_prototype is not None
            else port_interface.name.replace("i", "p", 1),
        )

        if middleware_sender_port is None:
            # Create sender Port Prototype on Middleware
            middleware_sender_port = self.create_port_prototype(
                mfwk_adapter=mfwk_adapter,
                port_prototype_configuration=self.PortPrototypeConfiguration(
                    component_type=ct_cd_middleware,
                    port_interface=port_interface,
                    port_prototype_name=middleware_sender_name,
                    port_specification=sender_receiver_connection.sender_port,
                    interface_type=PortPrototype.__SENDER_RECEIVER__,
                    port_direction=PortPrototype.__PRODUCER__,
                ),
                existing_init_values=existing_init_values,
            )
            # Add Variable Access
            self.create_variable_accesses_from_configuration(
                mfwk_adapter=mfwk_adapter,
                port_interface=port_interface,
                port_prototype=middleware_sender_port,
                runnables=ct_cd_middleware.internal_behavior.runnables,
                variable_access_config=sender_receiver_connection.sender_port.variable_access,
            )
            # Add Port API Option
            self.create_port_api_option_from_configuration(
                port_prototype=middleware_sender_port,
                port_api_option_config=sender_receiver_connection.port_api_option,
            )

        if middleware_receiver_port is None:
            # Create receiver Port Prototype on Middleware
            middleware_receiver_port = self.create_port_prototype(
                mfwk_adapter=mfwk_adapter,
                port_prototype_configuration=self.PortPrototypeConfiguration(
                    component_type=ct_cd_middleware,
                    port_interface=port_interface,
                    port_prototype_name=middleware_receiver_name,
                    port_specification=sender_receiver_connection.receiver_port,
                    interface_type=PortPrototype.__SENDER_RECEIVER__,
                    port_direction=PortPrototype.__RECEIVER__,
                ),
                existing_init_values=existing_init_values,
            )
            # Add Variable Access
            self.create_variable_accesses_from_configuration(
                mfwk_adapter=mfwk_adapter,
                port_interface=port_interface,
                port_prototype=middleware_receiver_port,
                runnables=ct_cd_middleware.internal_behavior.runnables,
                variable_access_config=sender_receiver_connection.receiver_port.variable_access,
            )
            # Add Port API Option
            self.create_port_api_option_from_configuration(
                port_prototype=middleware_receiver_port,
                port_api_option_config=sender_receiver_connection.port_api_option,
            )

        mfwk_adapter.sync_element(receiver_component_type)
        mfwk_adapter.sync_element(sender_component_type)
        mfwk_adapter.sync_element(ct_cd_middleware)

        # Adding Assembly Connectors to ECU Composition.
        receiver_component_prototype = mfwk_adapter.used_by(receiver_component_type)[0]
        sender_component_prototype = mfwk_adapter.used_by(sender_component_type)[0]
        cp_cd_middleware = mfwk_adapter.used_by(ct_cd_middleware)[0]
        ecu_composition = cp_cd_middleware.parent

        ecu_composition.add_element(
            asr_element=AssemblyConnector(
                name="{}D{}D{}D{}".format(
                    sender_component_prototype.name,
                    sender_port_prototype.name,
                    cp_cd_middleware.name,
                    middleware_receiver_port.name,
                ),
                provider_port_ref=AutosarReference(
                    path=sender_port_prototype.ar_path, dest=AC.P_PORT_PROTOTYPE
                ),
                provider_component_ref=AutosarReference(
                    path=sender_component_prototype.ar_path,
                    dest=AC.SW_COMPONENT_PROTOTYPE,
                ),
                requester_port_ref=AutosarReference(
                    path=middleware_receiver_port.ar_path, dest=AC.R_PORT_PROTOTYPE
                ),
                requester_component_ref=AutosarReference(
                    path=cp_cd_middleware.ar_path, dest=AC.SW_COMPONENT_PROTOTYPE
                ),
            )
        )
        ecu_composition.add_element(
            asr_element=AssemblyConnector(
                name="{}D{}D{}D{}".format(
                    cp_cd_middleware.name,
                    middleware_sender_port.name,
                    receiver_component_prototype.name,
                    receiver_port_prototype.name,
                ),
                provider_port_ref=AutosarReference(
                    path=middleware_sender_port.ar_path, dest=AC.P_PORT_PROTOTYPE
                ),
                provider_component_ref=AutosarReference(
                    path=cp_cd_middleware.ar_path, dest=AC.SW_COMPONENT_PROTOTYPE
                ),
                requester_port_ref=AutosarReference(
                    path=receiver_port_prototype.ar_path, dest=AC.R_PORT_PROTOTYPE
                ),
                requester_component_ref=AutosarReference(
                    path=receiver_component_prototype.ar_path,
                    dest=AC.SW_COMPONENT_PROTOTYPE,
                ),
            )
        )
        mfwk_adapter.sync_element(ecu_composition)

    def create_port_prototype(
        self,
        mfwk_adapter,
        port_prototype_configuration,
        existing_init_values,
    ):
        """
        This method is used to create new Port Prototype on passed
        Component Type with specification parsed from Configuration XML node.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter
            which contains loaded ARXML files.
        :param self.PortPrototypeConfiguration port_prototype_configuration:
            Instance of PortPrototypeConfiguration which contains all needed
            properties for Port Prototype creation.
        :param dict existing_init_values: Dictionary of initial values with key
            of data element ar_path, and values in form of tuple, where first
            value is init_type and second one is init_value.
        :return: Instance of PortPrototype which is created.
        :rtype: PortPrototype
        """
        communication_specs = []
        communication_specs_config = (
            port_prototype_configuration.port_specification.communication_spec
        )
        for data_element in port_prototype_configuration.port_interface.members:
            communication_specs.append(
                self.create_comm_spec_from_configuration(
                    mfwk_adapter=mfwk_adapter,
                    data_element=data_element,
                    communication_specs_config=communication_specs_config,
                    existing_init_values=existing_init_values,
                )
            )

        port_prototype = PortPrototype(
            name=port_prototype_configuration.port_prototype_name,
            port_interface=AutosarReference(
                path=port_prototype_configuration.port_interface.ar_path,
                dest=AC.SENDER_RECEIVER_INTERFACE,
            ),
            interface_type=port_prototype_configuration.interface_type,
            direction=port_prototype_configuration.port_direction,
            communication_specs=communication_specs,
        )

        LOGGER.info(
            "Added %s port %s to component %s",
            port_prototype.direction,
            port_prototype.name,
            port_prototype_configuration.component_type.name,
        )
        port_prototype_configuration.component_type.add_element(port_prototype)

        return port_prototype

    def create_comm_spec_from_configuration(
        self,
        mfwk_adapter,
        data_element,
        communication_specs_config,
        existing_init_values,
    ):
        """
        This method is used to create CommunicationSpec instance from passed
        configuration parsed from XML configuration file.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter which
            contains all loaded AUTOSAR objects needed to create CommunicationSpec.
        :param VariableDataPrototype data_element: Instance of VariableDataPrototype
            which represents data element for which CommunicationSpec shall be
            created.
        :param object communication_specs_config: Instance of appripriate
            Configuration that is parsed from XML configuration file.
        :param dict existing_init_values: Dictionary of initial values with key
            of data element ar_path, and values in form of tuple, where first
            value is init_type and second one is init_value.
        :return: Instance of CommunicationSpec object filled
        """
        data_type = mfwk_adapter.get_by_ar_path(
            ImplementationType, data_element.type_ref.path
        )

        if existing_init_values and data_element.ar_path in existing_init_values:
            LOGGER.debug("Using existing initial value for %s", data_element.ar_path)
            init_value = existing_init_values[data_element.ar_path]
        else:
            LOGGER.debug("Creating new initial value for %s", data_element.ar_path)
            constant_reference = create_constant_for_data_type(
                constant_name=AC.CONSTANT_PREFIX
                + data_type.name[len(AC.DATA_TYPE_PREFIX) :],
                implementation_data_type=data_type,
                mfwk_adapter=mfwk_adapter,
            )
            init_value = Constant.Field(
                category=AC.CONSTANT_REFERENCE,
                constant_ref=constant_reference,
            )

        if isinstance(communication_specs_config, QueuedSenderCommSpec):
            communication_spec = CommunicationSpec(
                kind=communication_specs_config.kind,
                data_element_reference=data_element.ar_path,
                init_value=init_value,
                handle_out_of_range=communication_specs_config.handle_out_of_range,
                transmission_acknowledge=communication_specs_config.transmission_acknowledge,
                uses_end_to_end_protection=communication_specs_config.uses_end_to_end_protection,
            )
        elif isinstance(communication_specs_config, NonQueuedSenderCommSpec):
            communication_spec = CommunicationSpec(
                kind=communication_specs_config.kind,
                data_element_reference=data_element.ar_path,
                init_value=init_value,
                handle_out_of_range=communication_specs_config.handle_out_of_range,
                transmission_acknowledge=communication_specs_config.transmission_acknowledge,
                uses_end_to_end_protection=communication_specs_config.uses_end_to_end_protection,
            )
        elif isinstance(communication_specs_config, QueuedReceiverCommSpec):
            communication_spec = CommunicationSpec(
                kind=communication_specs_config.kind,
                data_element_reference=data_element.ar_path,
                init_value=init_value,
                handle_out_of_range=communication_specs_config.handle_out_of_range,
                uses_end_to_end_protection=communication_specs_config.uses_end_to_end_protection,
                queue_length=communication_specs_config.queue_length,
            )
        elif isinstance(communication_specs_config, NonQueuedReceiverCommSpec):
            communication_spec = CommunicationSpec(
                kind=communication_specs_config.kind,
                data_element_reference=data_element.ar_path,
                init_value=init_value,
                handle_out_of_range=communication_specs_config.handle_out_of_range,
                uses_end_to_end_protection=communication_specs_config.uses_end_to_end_protection,
                alive_timeout=communication_specs_config.alive_timeout,
                enable_update=communication_specs_config.enable_update,
                data_filter_type=communication_specs_config.data_filter_type,
                handle_never_received=communication_specs_config.handle_never_received,
                handle_timeout_type=communication_specs_config.handle_timeout_type,
            )
        else:
            communication_spec = None

        return communication_spec

    def create_variable_accesses_from_configuration(
        self,
        mfwk_adapter,
        port_interface,
        port_prototype,
        runnables,
        variable_access_config,
    ):
        """
        This method is used to create VariableAccess instances from passed
        configuration parsed from XML configuration file.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter which
            contains all loaded AUTOSAR objects needed to create VariableAccess
            instances.
        :param PortInterface port_interface: Instance of PortInterface which
            contains all Data Elements for which Variable Access shall be added.
        :param PortPrototype port_prototype: Instance of PortPrototype which is
            used to create Variable Access.
        :param list runnables: List of runnables used to find first periodic
            Runnable or desired one from configuration.
        :param object variable_access_config: Instance of appripriate
            Configuration that is parsed from XML configuration file.
        """
        runnable = None
        if variable_access_config.runnable:
            runnable = AutosarElement.find_element_by_key(
                value=variable_access_config.runnable,
                element_list=runnables,
                key=AC.NAME,
            )

        if is_middleware(port_prototype.parent):
            access = variable_access_config.middleware_kind
        else:
            access = variable_access_config.kind

        for data_element in port_interface.members:
            create_variable_access(
                adapter_host=mfwk_adapter,
                port_prototype=port_prototype,
                data_element=data_element,
                access=access,
                runnable=runnable,
            )

    def create_port_api_option_from_configuration(
        self, port_prototype, port_api_option_config
    ):
        """
        This method is used to create PortAPIOption for passed instance of Port
        Prototype from passed configuration parsed from XML configuration file.

        :param PortPrototype port_prototype: Instance of PortPrototype for which
            PortAPIOption shall be added.
        :param object port_api_option_config: Instance of appripriate
            Configuration that is parsed from XML configuration file.
        """
        # Port API Option does not exist
        if port_api_option_config is None:
            return

        if port_prototype.parent is None:
            LOGGER.error(
                "Please add Port Prototype %s to Component Type in "
                "order to add Port API Option.",
                port_prototype.name,
            )
            return

        if port_prototype.direction == PortPrototype.__RECEIVER__:
            port_ref_dest = PortAPIOption.__R_PORT_PROTOTYPE__
        else:
            port_ref_dest = PortAPIOption.__P_PORT_PROTOTYPE__

        port_api_option = PortAPIOption(
            enable_take_address=port_api_option_config.enable_take_address,
            packing_byte_order=port_api_option_config.error_handling,
            indirect_api=port_api_option_config.indirect_api,
            port_ref=port_prototype.ar_path,
            port_ref_dest=port_ref_dest,
        )

        port_prototype.parent.internal_behavior.add_element(port_api_option)

    def create_client_server_connection(self, mfwk_adapter, client_server_connection):
        """
        This method is used to create connection between Client Port and
        Server Port, based on configuration in client_server_connection.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter
            which contains loaded ARXML files.
        :param ClientServerConnection client_server_connection: Instance
            of ClientServerConnection which contains all needed
            properties.
        :return: /
        """

        LOGGER.info(
            "Creating connection between server %s and client %s via port %s",
            client_server_connection.server_port,
            client_server_connection.client_port.parent_swc_name,
            client_server_connection.port_interface,
        )

        port_interface = mfwk_adapter.get_by_name(
            class_=PortInterface, name=client_server_connection.port_interface
        )

        if port_interface is None:
            LOGGER.error(
                "Desired Port Interface %s does not exist in loaded "
                "ARXML files. Connection will not be created.",
                client_server_connection.port_interface,
            )
            return

        server_component_type = mfwk_adapter.get_by_name(
            class_=ComponentType,
            name=client_server_connection.server_port,
        )

        if server_component_type is None:
            LOGGER.error(
                "Server Component Type with name %s does not exist in "
                "loaded ARXML files. Connection will not be created.",
                client_server_connection.server_port,
            )
            return

        client_component_type = mfwk_adapter.get_by_name(
            class_=ComponentType,
            name=client_server_connection.client_port.parent_swc_name,
        )

        if client_component_type is None:
            LOGGER.error(
                "Client Component Type with name %s does not exist in "
                "loaded ARXML files. Connection will not be created.",
                client_server_connection.client_port.parent_swc_name,
            )
            return

        server_port_prototype = None
        for port in server_component_type.ports:
            if port.port_interface.path == port_interface.ar_path:
                server_port_prototype = port
                break

        client_port_prototype = None
        for port in client_component_type.ports:
            if port.port_interface.path == port_interface.ar_path:
                client_port_prototype = port
                break

        if server_port_prototype is None:
            LOGGER.error(
                "Server port prototype of port interface %s does not exist in "
                "%s server component type. Connection will not be created.",
                port_interface.name,
                server_component_type.name,
            )
            return

        if client_port_prototype is None:
            prototype_name = ""
            if client_server_connection.port_prototype:
                prototype_name = client_server_connection.port_prototype
            elif port_interface.name.startswith("Pi"):
                prototype_name = port_interface.name.replace("Pi", "Pp")
            else:
                prototype_name = "{}{}".format("Pp", port_interface.name)

            port_config = self.PortPrototypeConfiguration(
                component_type=client_component_type,
                port_interface=port_interface,
                port_prototype_name=prototype_name,
                port_specification=client_server_connection.client_port,
                interface_type=PortPrototype.__CLIENT_SERVER__,
                port_direction=PortPrototype.__RECEIVER__,
            )
            # Create client port prototype.
            client_port_prototype = self.create_client_port_prototype(
                mfwk_adapter=mfwk_adapter,
                port_config=port_config,
            )
            # Add server call points for the new client port prototype.
            self.add_server_call_points_to_runnable(
                mfwk_adapter=mfwk_adapter,
                port_prototype=client_port_prototype,
                port_config=port_config,
            )
            # Add port API option for the new client port prototype.
            self.create_port_api_option_from_configuration(
                port_prototype=client_port_prototype,
                port_api_option_config=client_server_connection.port_api_option,
            )
            mfwk_adapter.sync_element(asr_element=client_component_type)
        else:
            LOGGER.info(
                "Client port prototype %s, already exist in the client "
                "component type %s, so it won't be created.",
                client_port_prototype.name,
                client_component_type.name,
            )
        # Create Assembly connector.
        self.create_connector(
            provider_port=server_port_prototype,
            requester_port=client_port_prototype,
            mfwk_adapter=mfwk_adapter,
        )

    def create_client_port_prototype(
        self,
        mfwk_adapter,
        port_config,
    ):
        """
        This method is used to create new Client Port Prototype on passed
        Component Type with specification parsed from CLIENT-SERVER-CONNECTION
        XML node.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter
            which contains loaded ARXML files.
        :param self.PortPrototypeConfiguration port_config: Instance
            of PortPrototypeConfiguration which contains all needed properties
            for Port Prototype creation.
        :return: Instance of the created client ::class:`PortPrototype`
        :rtype: PortPrototype
        """
        # Create the prototype with communication specification elements for each
        # client/server operation.
        port_prototype = PortPrototype(
            name=port_config.port_prototype_name,
            port_interface=AutosarReference(
                path=port_config.port_interface.ar_path,
                dest=AC.CLIENT_SERVER_INTERFACE,
            ),
            interface_type=port_config.interface_type,
            direction=port_config.port_direction,
            communication_specs=[
                CommunicationSpec(
                    kind=CommunicationSpec.__CLIENT_SPEC__,
                    operation_reference=client_server_operation.ar_path,
                )
                for client_server_operation in port_config.port_interface.members
            ],
        )
        mfwk_adapter.add_element(
            asr_element=port_prototype, parent=port_config.component_type
        )
        return port_prototype

    def add_server_call_points_to_runnable(
        self, mfwk_adapter, port_prototype, port_config
    ):
        """
        This method is used to create a server call point for each client/server
        operation of the port prototype and add it to the runnable of the component type
        where the port prototype is instantiated. If the runnable name is not explicitly
        specified in the port configuration, then server call points are added to the
        first periodic runnable of the component type.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of MFWK Adapter
            which contains loaded ARXML files.
        :param PortPrototype port_prototype: Instance of the client port prototype whose
            client/server operations are used to create server call points.
        :param self.PortPrototypeConfiguration port_config: Instance
            of PortPrototypeConfiguration which contains all needed properties
            for Port Prototype creation.
        :return: /
        """
        # Create the server call points in runnable with the specified access type.
        server_call_point_config = port_config.port_specification.server_call_point
        if server_call_point_config.runnable:
            runnable = AutosarElement.find_element_by_key(
                element_list=port_config.component_type.internal_behavior.runnables,
                value=server_call_point_config.runnable,
                key=AC.NAME,
            )
            if runnable is None:
                LOGGER.error(
                    "Runnable %s does not exist in "
                    "%s client component type. "
                    "Connection will not be created.",
                    server_call_point_config.runnable,
                    port_config.component_type.name,
                )
                return
        else:
            runnable = get_first_periodic_runnable(
                component_type=port_config.component_type
            )
            if runnable is None:
                LOGGER.error(
                    "Could not find periodic runnable in "
                    "%s client component type. "
                    "Connection will not be created.",
                    port_config.component_type.name,
                )
                return

        new_server_call_points = [
            self.create_server_call_point(
                server_call_point_config=server_call_point_config,
                port_prototype=port_prototype,
                client_server_operation=client_server_operation,
            )
            for client_server_operation in port_config.port_interface.members
        ]
        LOGGER.info(
            "Adding server call points to the runnable %s.",
            runnable.name,
        )
        runnable.server_call_points.extend(new_server_call_points)
        if server_call_point_config.kind == "ASYNCHRONOUS":
            # Add result points in case of async server call point.
            new_result_points = [
                AsynchronousServerCallResultPoint(
                    name="ASCRP_{}_{}".format(runnable.name, scp.name),
                    asynchronous_server_call_point_ref=scp.operation.cs_operation_ref.path,
                )
                for scp in new_server_call_points
            ]
            runnable.asynchronous_server_call_result_points.extend(new_result_points)

        mfwk_adapter.sync_element(asr_element=port_config.component_type)

    @staticmethod
    def create_server_call_point(
        server_call_point_config, port_prototype, client_server_operation
    ):
        """
        Helper method used to create the server call point based on the given
        configuration.

        :param xml_parse_utilities.ServerCallPoint server_call_point_config:
        :param PortPrototype port_prototype:
        :param ClientServerOperation client_server_operation:
        :return: Created instance of the ::class:`ServerCallPoint`
        :rtype: ServerCallPoint
        """
        point_kind = (
            ServerCallPoint.__SYNC_TYPE__
            if server_call_point_config.kind == "SYNCHRONOUS"
            else ServerCallPoint.__ASYNC_TYPE__
        )
        return ServerCallPoint(
            name="{}_{}_{}".format(
                "SC" if point_kind == ServerCallPoint.__SYNC_TYPE__ else "AC",
                port_prototype.name,
                client_server_operation.name,
            ),
            variant=point_kind,
            operation=ServerCallPoint.Operation(
                port_prototype_ref=ServerCallPoint.Operation.PortPrototypeRef(
                    variant=ServerCallPoint.Operation.__PORT_RECEIVER__,
                    path=port_prototype.ar_path,
                    parser_element=None,
                ),
                cs_operation_ref=ServerCallPoint.Operation.CSOperationRef(
                    variant=ServerCallPoint.Operation.__OPERATION_REQUIRED__,
                    path=client_server_operation.ar_path,
                    parser_element=None,
                ),
            ),
            timeout=server_call_point_config.timeout
            if server_call_point_config.timeout
            else 0,
        )

    def create_connector(self, provider_port, requester_port, mfwk_adapter):
        """
        This method is used to create assembly connector between two ports on the
        components that belong to the root host composition type.

        :param PortPrototype provider_port: /
        :param PortPrototype requester_port: /
        :param ArxmlAsrAdapter mfwk_adapter: /
        :return: Instance of the ::class:`AssemblyConnector`
        :rtype: AssemblyConnector
        """
        # Find the composition where the components are instantiated to created the
        # connection between them.
        req_usage = mfwk_adapter.used_by(requester_port.parent)
        prov_usage = mfwk_adapter.used_by(provider_port.parent)
        requester_component_prototype = req_usage[0] if req_usage else None
        provider_component_prototype = prov_usage[0] if prov_usage else None

        if (
            requester_component_prototype is None
            or provider_component_prototype is None
        ):
            LOGGER.error(
                "Could not create the connection between server and client "
                "components, because their prototypes are not found"
            )
            return

        if requester_component_prototype.parent != provider_component_prototype.parent:
            LOGGER.error(
                "Could not create the connection between server and client "
                "components, because they are not part of the same root host "
                "composition type"
            )
            return

        root_composition = provider_component_prototype.parent

        connector = AssemblyConnector(
            name="{}D{}D{}D{}".format(
                provider_component_prototype.name,
                provider_port.name,
                requester_component_prototype.name,
                requester_port.name,
            ),
            provider_component_ref=AutosarReference(
                path=provider_component_prototype.ar_path,
                dest=AC.SW_COMPONENT_PROTOTYPE,
            ),
            provider_port_ref=AutosarReference(
                path=provider_port.ar_path, dest=AC.P_PORT_PROTOTYPE
            ),
            requester_component_ref=AutosarReference(
                path=requester_component_prototype.ar_path,
                dest=AC.SW_COMPONENT_PROTOTYPE,
            ),
            requester_port_ref=AutosarReference(
                path=requester_port.ar_path, dest=AC.R_PORT_PROTOTYPE
            ),
        )
        mfwk_adapter.add_element(
            asr_element=connector, parent=root_composition, overwrite=False
        )

    """
    This class is used to implement the rule for removing defined Runnable entities
    from the software component type.
    """

    def touch(self, mfwk_adapter):
        """
        The method that executes modeling actions for removing runnable entities
        from the software component types, and and events that are used to trigger them.

        :param ArxmlAsrAdapter mfwk_adapter: Instance of the Modeling Framework adapter.
        :return: /
        """
        if self.configuration is None:
            LOGGER.info(
                "%s - Cannot be executed, because it requires "
                "the component types with runnables to remove "
                "to be specified.",
                TouchRemoveRunnables.__name__,
            )
            return

        for component_config in self.configuration:
            component_type = mfwk_adapter.get_by_name(
                class_=ComponentType, name=component_config.type_name
            )
            if component_type is None:
                LOGGER.info(
                    "%s - Component type %s cannot be found in the model.",
                    TouchRemoveRunnables.__name__,
                    component_config.type_name,
                )
                continue
            for runnable_name in component_config.runnables:
                runnable = AutosarElement.find_element_by_key(
                    value=runnable_name,
                    element_list=component_type.internal_behavior.runnables,
                    key=AC.NAME,
                )
                if runnable is not None:
                    mfwk_adapter.delete_element(asr_element=runnable)
                else:
                    LOGGER.info(
                        "%s - Runnable %s is not present in the component type %s.",
                        TouchRemoveRunnables.__name__,
                        runnable_name,
                        component_type.name,
                    )

    def extract_config_rule(self, configuration_adapter, configuration_bundle):
        """
        Method for setting up :class:`TouchRemoveRunnables`
        rule's configuration parameters.

        :param TouchRulesConfigurationAdapter configuration_adapter: Adapter for
            parsing the configuration file and extracting configuration parameters for
            the specific rule.
        :param object configuration_bundle: The part of the configuration that is
            specific for the rule.
        :return: /
        """
        self.configuration = configuration_adapter.extract_touch_remove_runnables(
            configuration_bundle
        )

</rules>