# Java, .NET and native code

Call Java, .NET or native clients from services as named connections.

When the client for a system is a Java jar the vendor ships, a .NET assembly or a native binary, `start_process` from the [Connector SDK](https://zato.io/docs/sdk/index.html) runs it as a helper process next to the server. The process starts and stops with the connection, the platform supervises it and services use the connection like any other.

## The connector module {#the-connector-module}

The connector wraps a Java inventory component - a jar that serves requests over a local socket:

```python
# -*- coding: utf-8 -*-

# stdlib
import socket
import time

# Zato
from zato.common.sdk import Connector, Field

# How long to wait for the helper process to start accepting connections, in seconds.
_startup_timeout = 15

class InventoryClient:
    """ A client for the inventory system, which is a Java component - the connector runs its jar
    as a helper process and this client calls it over a local socket, one connection per request.
    """
    def __init__(self, host:'str', port:'int') -> 'None':
        self.host = host
        self.port = port

    def send(self, data:'str') -> 'str':

        # Connect for the duration of one request ..
        with socket.create_connection((self.host, self.port)) as conn:
            conn.sendall(f'{data}\n'.encode('utf8'))

            # .. and read the response line back.
            with conn.makefile('r', encoding='utf8') as reader:
                response = reader.readline()

        return response.strip()

class InventoryConnector(Connector):
    """ Wraps a Java inventory component - a jar run and supervised as a helper process
    that services access through self.out.inventory.
    """
    type = 'inventory'

    # Configuration schema
    jar_path = Field.Text()

    def create_client(self) -> 'InventoryClient':

        # Run the jar as a supervised helper process - the '{port}' placeholder holds
        # the local port allocated for it.
        process = self.start_process(['java', '-jar', self.config.jar_path, '{port}'])

        client = InventoryClient('127.0.0.1', process.port)

        # Wait until the JVM accepts connections.
        deadline = time.monotonic() + _startup_timeout

        while True:
            try:
                client.send('hello')
            except OSError:
                if time.monotonic() > deadline:
                    raise Exception(f'The inventory helper did not start within {_startup_timeout}s')
                time.sleep(0.2)
            else:
                break

        self.logger.info('Inventory helper started for `%s` (pid %s)', self.name, process.pid)
        return client

    def ping(self, client:'InventoryClient') -> 'None':
        client.send('ping')

    def get_stock(self, item:'str') -> 'str':
        return self.client.send(f'stock {item}')
```

The platform provides `start_process` - it allocates a local port, substitutes it for the `{port}` placeholder in the command and starts the process. The returned object has four attributes - `pid`, `port`, `is_running` and `stop`.

The platform supervises the process. When the process exits unexpectedly, the platform rebuilds the whole connection with backoff, which re-runs `create_client` and starts a new helper. Deleting or editing the definition stops the process together with the connection.

A .NET assembly or a native binary uses the same connector code - only the command changes.

## Create a definition {#create-a-definition}

Create the definition in an [enmasse](https://zato.io/docs/admin/enmasse.html) file, under the `custom_inventory` key - `custom_` followed by the connector's type:

```yaml
custom_inventory:
  - name: My Inventory
    jar_path: /opt/vendor/inventory-client.jar
```

The jar runs and stops with the connection and services call it like any other connection type.

## See also {#see-also}

- [SDK reference](https://zato.io/docs/sdk/reference.html) - Field types, lifecycle methods and the behavior of every invocation
- [Command-line tools](https://zato.io/docs/sdk/cli-tools.html) - One-shot commands and long-lived tools like ngrok as connections
- [Python libraries in a separate interpreter](https://zato.io/docs/sdk/python-cannot-run-in-server.html) - Run a Python library in an interpreter of its own and call it from services
