Creating a component

How to create a component and assemble a service from it.

Key takeaways

Component creation How to create a component and define its behavior throughout its lifecycle.
Containerization How to add a component to a container and execute it.

Introduction

In this tutorial, we will learn how to create a component and how to assemble a service from it. We will start with a short description of a component’s lifecycle and then we will create a component by defining step-by-step all the elements that compose its lifecycle. Finally, we will assemble a service from it through a container, run it, and see the results.

The lifecycle of a component

A component lifecycle is implemented using interfaces. In this manner, an existing class can be turned into a Pip.Services component (code augmentation). The following diagram summarizes the main states of a component and their respective interfaces

Console logger messages

Creating our component

Following the sequence presented in the previous figure, we will create a component and explain each step of its lifecycle.

Step 1 – Creating the component

A component can be seen as a class that has a default constructor. Thus, we will begin by creating a class with a constructor, such as:

class MyComponentA {
    private _param1: string = "ABC";
    private _param2: number = 123;
    private _open: boolean = false;
    private _status: string;

    // Creates a new instance of the component.
    public constructor(){
        this._status = "Created";
        console.log("MyComponentA has been created.");
    }
}


public class MyComponentA
{
    private string _param1 = "ABC";
    private int _param2 = 123;
    private bool _open=false;
    private string _status;

    // Creates a new instance of the component.
    public MyComponentA()
    {
        _status = "Created";
        Console.WriteLine("MyComponentA has been created.");
    }
}


type MyComponentA struct {
	param1 string
	param2 int
	open   bool

	status string
}

func NewMyComponentA() *MyComponentA {
	fmt.Println("MyComponentA has been created.")

	return &MyComponentA{
		param1: "ABC",
		param2: 123,
		open:   false,
		status: "Created",
	}
}

class MyComponentA {
  String _param1 = 'ABC';
  int _param2 = 123;
  bool _open = false;
  String? _status;

  // Creates a new instance of the component.
  MyComponentA() {
    _status = 'Created';
    print('MyComponentA has been created.');
  }
}


class MyComponentA():
    _param1 = 'ABC'
    _param2 = 123
    _open = False
    _status = None
    
    def __init__(self):
        """
        Creates a new instance of the component.
        """
        self._status = "Created"
        print("MyComponentA has been created.")
        

Not available

Step 2 – Configuration

Now that we have a component, we will add configuration capabilities to it. For this, we need to use the Iconfigurable interface and define the configure method. In this method, we will receive a ConfigParams object (key-value map) with the values of the parameters and assign them to our variables.

import { ConfigParams, IConfigurable } from "pip-services3-commons-nodex";

class MyComponentA implements IConfigurable {
    private _param1: string = "ABC";
    private _param2: number = 123;
    private _open: boolean = false;
    private _status: string;

    // Creates a new instance of the component.
    public constructor(){
        this._status = "Created";
        console.log("MyComponentA has been created.");
    }

    public configure(config: ConfigParams): void {
        this._param1 = config.getAsStringWithDefault("param1", "ABC");
        this._param2 = config.getAsIntegerWithDefault("param2", 123);
        this._status = "Configured";

        console.log("MyComponentA has been configured.");
    }
}

    using PipServices3.Commons.Config;
    using System;

public class MyComponentA: IConfigurable
{
    private string _param1 = "ABC";
    private int _param2 = 123;
    private bool _open=false;
    private string _status;

    // Creates a new instance of the component.
    public MyComponentA()
    {
        _status = "Created";
        Console.WriteLine("MyComponentA has been created.");
    }

    public void Configure(ConfigParams config)
    {
        _param1 = config.GetAsStringWithDefault("param1", "ABC");
        _param2 = config.GetAsIntegerWithDefault("param2", 123);
        _status = "Configured";

        Console.WriteLine("MyComponentA has been configured.");
    }
}

import (
	"fmt"

	config "github.com/pip-services3-gox/pip-services3-commons-gox/config"
)

type MyComponentA struct {
	config.IConfigurable

	param1 string
	param2 int
	open   bool

	status string
}

// Creates a new instance of the component.
func NewMyComponentA() *MyComponentA {
	fmt.Println("MyComponentA has been created.")

	return &MyComponentA{
		param1: "ABC",
		param2: 123,
		open:   false,
		status: "Created",
	}
}

func (c *MyComponentA) Configure(ctx context.Context, config *config.ConfigParams) {
	c.param1 = config.GetAsStringWithDefault("param1", "ABC")
	c.param2 = config.GetAsIntegerWithDefault("param2", 123)
	c.status = "Configured"
	fmt.Println("MyComponentA has been configured.")
}

import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyComponentA implements IConfigurable {
  String _param1 = 'ABC';
  int _param2 = 123;
  bool _open = false;
  String? _status;

  // Creates a new instance of the component.
  MyComponentA() {
    _status = 'Created';
    print('MyComponentA has been created.');
  }

  @override
  void configure(ConfigParams config) {
    _param1 = config.getAsStringWithDefault('param1', 'ABC');
    _param2 = config.getAsIntegerWithDefault('param2', 123);
    _status = 'Configured';

    print('MyComponentA has been configured.');
  }
}


from pip_services3_commons.config import IConfigurable, ConfigParams

class MyComponentA(IConfigurable):
    _param1 = 'ABC'
    _param2 = 123
    _open = False
    _status = None
    
    def __init__(self):
        """
        Creates a new instance of the component.
        """
        self._status = "Created"
        print("MyComponentA has been created.")
            
    def configure(self, config):
        self._param1 = config.get_as_string_with_default("param1", 'ABC')
        self._param2 = config.get_as_integer_with_default("param2", 123)
        self._status = "Configured"
        print("MyComponentA has been configured.")

Not available

Step 3 – Referencing

After configuring our component, we want to link MyComponentA to another component called MyComponentB. To do this, we need to use the IReferenceable interface. This interface contains the set_references method, which allows us to define references to dependent components. As a component’s locator, we will use a Descriptor object with the connection parameters. Our code will be like this:

import { 
    ConfigParams, Descriptor, IConfigurable, 
    IReferenceable, IReferences 
} from "pip-services3-commons-nodex";


class MyComponentB {
    private _param1: string = "ABC2";
    private _param2: number = 456;
    private _open: boolean = false;
    private _status: string;

    // Creates a new instance of the component.
    public constructor() {
        this._status = "Created";
        console.log("MyComponentB has been created.");
    }
}

class MyComponentA implements IConfigurable, IReferenceable {
    private _param1: string = "ABC";
    private _param2: number = 123;
    private _open: boolean = false;
    private _status: string;
    private _anotherComponent: MyComponentB;

    // Creates a new instance of the component.
    public constructor(){
        this._status = "Created";
        console.log("MyComponentA has been created.");
    }

    public setReferences(references: IReferences): void {
        this._anotherComponent = references.getOneRequired<MyComponentB>(
            new Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
        );

        this._status = "Configured";
        console.log("MyComponentA's references have been defined.");
    }

    public configure(config: ConfigParams): void {
        this._param1 = config.getAsStringWithDefault("param1", "ABC");
        this._param2 = config.getAsIntegerWithDefault("param2", 123);
        this._status = "Configured";

        console.log("MyComponentA has been configured.");
    }
}
using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using System;


public class MyComponentB
{
    private string _param1 = "ABC2";
    private int _param2 = 456;
    private bool _open = false;
    private string _status;

    // Creates a new instance of the component.
    public MyComponentB()
    {
        _status = "Created";
        Console.WriteLine("MyComponentB has been created.");
    }
}


public class MyComponentA : IReferenceable, IConfigurable
{
    private string _param1 = "ABC";
    private int _param2 = 123;
    private bool _open = false;
    private string _status;
    private MyComponentB _anotherComponent;

    // Creates a new instance of the component.
    public MyComponentA()
    {
        _status = "Created";
        Console.WriteLine("MyComponentA has been created.");
    }

    public void Configure(ConfigParams config)
    {
        _param1 = config.GetAsStringWithDefault("param1", "ABC");
        _param2 = config.GetAsIntegerWithDefault("param2", 123);
        _status = "Configured";

        Console.WriteLine("MyComponentA has been configured.");
    }

    public void SetReferences(IReferences references)
    {
        _anotherComponent = references.GetOneRequired<MyComponentB>(new Descriptor("myservice", "mycomponent-b", "*", "*", "1.0"));

        _status = "Configured";
        Console.WriteLine("MyComponentA's references have been defined.");
    }
}

import (
	"fmt"

	config "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
)

type MyComponentB struct {
	param1 string
	param2 int
	open   bool

	status string
}

type MyComponentA struct {
	config.IConfigurable
	refer.IReferenceable

	param1 string
	param2 int
	open   bool

	anotherComponent interface{}

	status string
}

// Creates a new instance of the component.
func NewMyComponentB() *MyComponentB {
	fmt.Println("MyComponentB has been created.")

	return &MyComponentB{
		param1: "ABC2",
		param2: 456,
		open:   false,
		status: "Created",
	}
}

// Creates a new instance of the component.
func NewMyComponentA() *MyComponentA {
	fmt.Println("MyComponentA has been created.")

	return &MyComponentA{
		param1: "ABC",
		param2: 123,
		open:   false,
		status: "Created",
	}
}

func (c *MyComponentA) Configure(ctx context.Context, config *config.ConfigParams) {
	c.param1 = config.GetAsStringWithDefault("param1", "ABC")
	c.param2 = config.GetAsIntegerWithDefault("param2", 123)
	c.status = "Configured"
	fmt.Println("MyComponentA has been configured.")
}

func (c *MyComponentA) SetReferences(ctx context.Context, references refer.IReferences) {
	component, err := references.GetOneRequired(
		refer.NewDescriptor("myservice", "mycomponent-b", "*", "*", "1.0"),
	)
	if err == nil {
		c.anotherComponent = component.(*MyComponentB)
		c.status = "Configured"
		fmt.Println("MyComponentA's references have been defined.")
	}

}
import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyComponentB {
  String _param1 = 'ABC2';
  int _param2 = 456;
  bool _open = false;
  String? _status;

  // Creates a new instance of the component.
  MyComponentB() {
    _status = 'Created';
    print('MyComponentB has been created.');
  }
}

class MyComponentA implements IConfigurable, IReferenceable {
  String _param1 = 'ABC';
  int _param2 = 123;
  bool _open = false;
  String? _status;
  MyComponentB? _anotherComponent;

  // Creates a new instance of the component.
  MyComponentA() {
    _status = 'Created';
    print('MyComponentA has been created.');
  }

  @override
  void setReferences(IReferences references) {
    _anotherComponent = references.getOneRequired<MyComponentB>(
        Descriptor('myservice', 'mycomponent-b', '*', '*', '1.0'));

    _status = 'Configured';
    print("MyComponentA's references have been defined.");
  }

  @override
  void configure(ConfigParams config) {
    _param1 = config.getAsStringWithDefault('param1', 'ABC');
    _param2 = config.getAsIntegerWithDefault('param2', 123);
    _status = 'Configured';

    print('MyComponentA has been configured.');
  }
}

from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import IReferenceable, IReferences, Descriptor

class MyComponentB():
    _param1 = 'ABC2'
    _param2 = 456
    _opened = False
    _status = None

    def __init__(self):
        """
        Creates a new instance of the component.
        """
        self._status = "Created"
        print("MyComponentB has been created.")

class MyComponentA(IReferenceable, IConfigurable):
    _param1 = 'ABC'
    _param2 = 123
    _another_component: MyComponentB
    _open = False
    _status = None
    
    def __init__(self):
        """
        Creates a new instance of the component.
        """
        self._status = "Created"
        print("MyComponentA has been created.")
            
    def configure(self, config):
        self._param1 = config.get_as_string_with_default("param1", 'ABC')
        self._param2 = config.get_as_integer_with_default("param2", 123)
        self._status = "Configured"
        print("MyComponentA has been configured.")
    def set_references(self, references):
        self._another_component = references.get_one_required(
            Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
        )
        self._status = "Configured"
        print("MyComponentA's references have been defined.")

Not available

Step 4 – Opening

To help define those components that require opening, PIP.services offers the IOpenable interface. This interface is part of the Commons module and offers two methods: open and isOpen. In our example, we will use the first one to create the code that will open the component, and the second one to verify whether the component is open or not.

Moreover, as the opening of the component marks the start of its usage, we will add an optional parameter called correlation_id. This parameter is used to trace the execution of the component through the call chain. It can be any string, such as “123”.

Now, our code expands to this:

import { 
    ConfigParams, Descriptor, IConfigurable, 
    IOpenable, IReferenceable, IReferences 
} from "pip-services3-commons-nodex";


class MyComponentB {
    // ...
}


class MyComponentA implements IConfigurable, IReferenceable, IOpenable {
    private _param1: string = "ABC";
    private _param2: number = 123;
    private _open: boolean = false;
    private _status: string;
    private _anotherComponent: MyComponentB;

    // Creates a new instance of the component.
    public constructor(){
        this._status = "Created";
        console.log("MyComponentA has been created.");
    }

    public isOpen(): boolean {
        return this._open;
    }

    public open(correlationId: string): Promise<void> {
        this._open = true;
        this._status = "Open";
        console.log("MyComponentA has been opened.");

        return;
    }

    public setReferences(references: IReferences): void {
        this._anotherComponent = references.getOneRequired<MyComponentB>(
            new Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
        );

        this._status = "Configured";
        console.log("MyComponentA's references have been defined.");
    }

    public configure(config: ConfigParams): void {
        this._param1 = config.getAsStringWithDefault("param1", "ABC");
        this._param2 = config.getAsIntegerWithDefault("param2", 123);
        this._status = "Configured";

        console.log("MyComponentA has been configured.");
    }
}

using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Run;
using System;
using System.Threading.Tasks;


public class MyComponentB
{
    // ...
}


public class MyComponentA : IReferenceable, IConfigurable, IOpenable
{
    private string _param1 = "ABC";
    private int _param2 = 123;
    private bool _open = false;
    private string _status;
    private MyComponentB _anotherComponent;

    // Creates a new instance of the component.
    public MyComponentA()
    {
        _status = "Created";
        Console.WriteLine("MyComponentA has been created.");
    }

    public void Configure(ConfigParams config)
    {
        _param1 = config.GetAsStringWithDefault("param1", "ABC");
        _param2 = config.GetAsIntegerWithDefault("param2", 123);
        _status = "Configured";

        Console.WriteLine("MyComponentA has been configured.");
    }

    public bool IsOpen()
    {
        return _open;
    }

    public async Task OpenAsync(string correlationId)
    {
        _open = true;
        _status = "Open";
        Console.WriteLine("MyComponentA has been opened.");
    }

    public void SetReferences(IReferences references)
    {
        _anotherComponent = references.GetOneRequired<MyComponentB>(new Descriptor("myservice", "mycomponent-b", "*", "*", "1.0"));

        _status = "Configured";
        Console.WriteLine("MyComponentA's references have been defined.");
    }
}

import (
	"fmt"

	config "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
	run "github.com/pip-services3-gox/pip-services3-commons-gox/run"
)


type MyComponentB struct {
    // ...
}
   

type MyComponentA struct {
	config.IConfigurable
	refer.IReferenceable
	run.IOpenable

	param1 string
	param2 int
	open   bool

	anotherComponent interface{}

	status string
}
    

func (c *MyComponentA) IsOpen() bool {
	return c.open
}

func (c *MyComponentA) Open(ctx context.Context, correlationId string) error {
	c.open = true
	c.status = "Open"
	fmt.Println("MyComponentA has been opened.")
	return nil
}


import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyComponentB {
  // ...
}

class MyComponentA implements IConfigurable, IReferenceable, IOpenable {
  String _param1 = 'ABC';
  int _param2 = 123;
  bool _open = false;
  String? _status;
  MyComponentB? _anotherComponent;

  // Creates a new instance of the component.
  MyComponentA() {
    _status = 'Created';
    print('MyComponentA has been created.');
  }

  @override
  void setReferences(IReferences references) {
    _anotherComponent = references.getOneRequired<MyComponentB>(
        Descriptor('myservice', 'mycomponent-b', '*', '*', '1.0'));

    _status = 'Configured';
    print("MyComponentA's references have been defined.");
  }

  @override
  void configure(ConfigParams config) {
    _param1 = config.getAsStringWithDefault('param1', 'ABC');
    _param2 = config.getAsIntegerWithDefault('param2', 123);
    _status = 'Configured';

    print('MyComponentA has been configured.');
  }

  @override
  bool isOpen() {
    return _open;
  }

  @override
  Future open(String? correlationId) async {
    _open = true;
    _status = 'Open';
    print('MyComponentA has been opened.');
  }
}


from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import IReferenceable, IReferences, Descriptor


class MyComponentB():
       
    # ...
       

class MyComponentA(IReferenceable, IConfigurable, IOpenable):
    _param1 = 'ABC'
    _param2 = 123
    _another_component: MyComponentB
    _open = False
    _status = None
    
    # ...

    def is_open(self):
        return self._open

    def open(self, correlation_id):
        self._open = True
        self._status = "Open"
        print("MyComponentA has been opened.")


Not available

Step 5 – Execution

We will now define a function that will be used to perform business tasks, and we will call it my_task. In our example, the business task will consist of printing a message and defining a dummy variable.

import { 
    ConfigParams, Descriptor, IConfigurable, 
    IOpenable, IReferenceable, IReferences 
} from "pip-services3-commons-nodex";

class MyComponentB {
    // ...
}
       
    
class MyComponentA implements IConfigurable, IReferenceable, IOpenable {
    private _param1: string = "ABC";
    private _param2: number = 123;
    private _open: boolean = false;
    private _status: string;
    private _anotherComponent: MyComponentB;
    
    public dummyVariable: string;

    // ...

    public myTask(correlationId: string): void {
        console.log("Doing my business task");
        this.dummyVariable = "dummy value";
    }
}

using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Run;
using System;
using System.Threading.Tasks;

public class MyComponentB
{
    // ...
}
       
    
    
public class MyComponentA : IReferenceable, IConfigurable, IOpenable
{
    private string _param1 = "ABC";
    private int _param2 = 123;
    private bool _open = false;
    private string _status;
    private MyComponentB _anotherComponent;
        
    public string DummyVariable;
    
    // ...

    public void MyTask(string correlationId)
    {
        Console.WriteLine("Doing my business task");
        DummyVariable = "dummy value";
    }
}

import (
	"fmt"

	config "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
	run "github.com/pip-services3-gox/pip-services3-commons-gox/run"
)

type MyComponentB struct {
    // ...
}
    
type MyComponentA struct {
	config.IConfigurable
	refer.IReferenceable
	run.IOpenable

	param1 string
	param2 int
	open   bool

	anotherComponent interface{}
	dummyVariable    string

	status string
}
    
// ...

func (c *MyComponentA) MyTask(ctx context.Context, correlationId string) {
	fmt.Println("Doing my business task")
	c.dummyVariable = "dummy value"
}

import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyComponentB {
  // ...
}

class MyComponentA implements IConfigurable, IReferenceable, IOpenable {
  String _param1 = 'ABC';
  int _param2 = 123;
  bool _open = false;
  String? _status;
  MyComponentB? _anotherComponent;

  String? dummyVariable;

  // ...

  void myTask(String correlationId) {
    print('Doing my business task');
    dummyVariable = 'dummy value';
  }
}


from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import IReferenceable, IReferences, Descriptor
from pip_services3_commons.run import IOpenable

class MyComponentB():
       
    # ...
    
class MyComponentA(IReferenceable, IConfigurable, IOpenable):
    _param1 = 'ABC'
    _param2 = 123
    _another_component: MyComponentB
    _open = False
    _status = None
    dummy_variable = ""
    
    # ...

    def my_task(self, correlation_id):
        print("Doing my business task")
        dummy_variable = "dummy value"

Not available

Step 6 – Closing

As any open component needs to be closed to ensure that the resources used are being freed for other processes, we now need to define our close method. To do this, we use the IClosable interface.

Here, we must note that the IClosable interface was already called by the IOpenable interface in step 4. Thus, we don’t need to explicitly call it now. As our component already has access to this interface, we will define the close method for our class. The code below shows a simplified version of this method.

import { 
    ConfigParams, Descriptor, IConfigurable, 
    IOpenable, IReferenceable, IReferences 
} from "pip-services3-commons-nodex";

class MyComponentB {
    // ...
}
       
    
class MyComponentA implements IConfigurable, IReferenceable, IOpenable {
    private _param1: string = "ABC";
    private _param2: number = 123;
    private _open: boolean = false;
    private _status: string;
    private _anotherComponent: MyComponentB;
    
    public dummyVariable: string;

    // ...

    public close(correlationId: string): Promise<void> {
        this._open = false;
        this._status = "Closed";
        console.log("MyComponentA has been closed.");

        return;
    }
}

using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Run;
using System;
using System.Threading.Tasks;

public class MyComponentB
{
    // ...
}
    

public class MyComponentA : IReferenceable, IConfigurable, IOpenable
{
    private string _param1 = "ABC";
    private int _param2 = 123;
    private bool _open = false;
    private string _status;
    private MyComponentB _anotherComponent;
    
    public string DummyVariable;
    
    // ...

    public async Task CloseAsync(string correlationId)
    {
        _open = false;
        _status = "Closed";
        Console.WriteLine("MyComponentA has been closed.");
    }
}

import (
	"fmt"

	config "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
	run "github.com/pip-services3-gox/pip-services3-commons-gox/run"
)

type MyComponentB struct {
    // ...
}
    
type MyComponentA struct {
	config.IConfigurable
	refer.IReferenceable
	run.IOpenable

	param1 string
	param2 int
	open   bool

	anotherComponent interface{}
	dummyVariable    string

	status string
}
    
// ...

func (c *MyComponentA) Close(ctx context.Context, correlationId string) error {
	c.open = false
	c.status = "Closed"
	fmt.Println("MyComponentA has been closed.")

	return nil
}

import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyComponentB {
  // ...
}

class MyComponentA implements IConfigurable, IReferenceable, IOpenable {
  String _param1 = 'ABC';
  int _param2 = 123;
  bool _open = false;
  String? _status;
  MyComponentB? _anotherComponent;

  String? dummyVariable;

  // ...

  @override
  Future close(String? correlationId) async {
    _open = false;
    _status = 'Closed';
    print('MyComponentA has been closed.');
  }
}

from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import IReferenceable, IReferences, Descriptor
from pip_services3_commons.run import IOpenable

class MyComponentB():
       
    # ...
    
class MyComponentA(IReferenceable, IConfigurable, IOpenable):
    _param1 = 'ABC'
    _param2 = 123
    _another_component: MyComponentB
    _open = False
    _status = None
    
    # ...
    
    def close(self, correlation_id):
        self._open = False
        self._status = "Closed"
        print("MyComponentA has been closed.")
        

Not available

Step 7 – Un-referencing

Once our component has been closed, we need to clear the component’s previously defined references. PIP.services provides the IUnreferenceable interface, which defines the unset_references method. In our example this method will be coded as:

import { 
    ConfigParams, Descriptor, IConfigurable, 
    IOpenable, IReferenceable, IReferences 
} from "pip-services3-commons-nodex";

class MyComponentB {
    // ...
}
       
    
class MyComponentA implements IConfigurable, IReferenceable, IOpenable, IUnreferenceable {
    private _param1: string = "ABC";
    private _param2: number = 123;
    private _open: boolean = false;
    private _status: string;
    private _anotherComponent: MyComponentB;
    
    public dummyVariable: string;

    // ...

    public unsetReferences(): void {
        this._anotherComponent = null;
        this._status = "Un-referenced";
        console.log("References cleared");
    }
}

using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Run;
using System;
using System.Threading.Tasks;

public class MyComponentB
{
    // ...
}
    
public class MyComponentA : IReferenceable, IConfigurable, IOpenable, IUnreferenceable
{
    private string _param1 = "ABC";
    private int _param2 = 123;
    private bool _open = false;
    private string _status;
    private MyComponentB _anotherComponent;
        
    public string DummyVariable;
    
    // ...

    // Unsets (clears) previously set references to dependent components.
    public void UnsetReferences()
    {
        _anotherComponent = null;
        _status = "Un-referenced";
        Console.WriteLine("References cleared");
    }
}

import (
	"fmt"

	config "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
	run "github.com/pip-services3-gox/pip-services3-commons-gox/run"
)

type MyComponentB struct {
    // ...
}
    
type MyComponentA struct {
	config.IConfigurable
	refer.IReferenceable
	refer.IUnreferenceable
	run.IOpenable

	param1 string
	param2 int
	open   bool

	anotherComponent interface{}
	dummyVariable    string

	status string
}
    
// ...
    
// Unsets (clears) previously set references to dependent components.
func (c *MyComponentA) UnsetReferences(ctx context.Context) {
	c.anotherComponent = nil
	c.status = "Un-referenced"
	fmt.Println("References cleared")

}

import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyComponentB {
  // ...
}

class MyComponentA implements IConfigurable, IReferenceable, IOpenable, IUnreferenceable {
  String _param1 = 'ABC';
  int _param2 = 123;
  bool _open = false;
  String? _status;
  MyComponentB? _anotherComponent;

  String? dummyVariable;

  // ...

  @override
  void unsetReferences() {
    _anotherComponent = null;
    _status = 'Un-referenced';
    print('References cleared');
  }
}

from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import IReferenceable, IReferences, Descriptor, IUnreferenceable
from pip_services3_commons.run import IOpenable

class MyComponentB():
       
    # ...
    
class MyComponentA(IReferenceable, IUnreferenceable, IConfigurable, IOpenable):
    _param1 = 'ABC'
    _param2 = 123
    _another_component: MyComponentB
    _open = False
    _status = None
    
    # ...
    
    def unset_references(self):
        """
        Unsets (clears) previously set references to dependent components.
        """
        self._another_component = None
        self._status = "Un-referenced"
        print("References cleared")

Not available

Step 8 – Destruction

Finally, to complete the process, we need to dispose of the component. For this, we will use a class destructors or other instruments provided by the languages. Our code will look something like this:

import { 
    ConfigParams, Descriptor, IConfigurable, 
    IOpenable, IReferenceable, IReferences 
} from "pip-services3-commons-nodex";

class MyComponentB {
    // ...
}
       

class MyComponentA implements IConfigurable, IReferenceable, IOpenable, IUnreferenceable {
    private _param1: string = "ABC";
    private _param2: number = 123;
    private _open: boolean = false;
    private _status: string;
    private _anotherComponent: MyComponentB;
    
    public dummyVariable: string;

    // ...

}


try {
    var component = new MyComponentA();
    // ...

    await component.close(null);
} finally {
    console.log("Component destroyed");
}






using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Run;
using System;
using System.Threading.Tasks;

public class MyComponentB
{
    // ...
}
    
public class MyComponentA : IReferenceable, IConfigurable, IOpenable, IUnreferenceable, IDisposable
{
    private string _param1 = "ABC";
    private int _param2 = 123;
    private bool _open = false;
    private string _status;
    private MyComponentB _anotherComponent;
        
    public string DummyVariable;
    
    // ...

    public void Dispose()
    {
        Console.WriteLine("Component destroyed");
    }
}

import (
	"fmt"

	config "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
	run "github.com/pip-services3-gox/pip-services3-commons-gox/run"
)

type MyComponentB struct {
    // ...
}
    
type MyComponentA struct {
	config.IConfigurable
	refer.IReferenceable
	refer.IUnreferenceable
	run.IOpenable

	param1 string
	param2 int
	open   bool

	anotherComponent interface{}
	dummyVariable    string

	status string
}

// ...

component := NewMyComponentA()

defer func() {
	if !component.IsOpen() {
		fmt.Println("Component destroyed")
	}
}()

// ...

component.Close(context.Background(), nil)
        
import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyComponentB {
  // ...
}

class MyComponentA implements IConfigurable, IReferenceable, IOpenable, IUnreferenceable {
  String _param1 = 'ABC';
  int _param2 = 123;
  bool _open = false;
  String? _status;
  MyComponentB? _anotherComponent;

  String? dummyVariable;

  // ...

}


try {
    var component = MyComponentA();
    // ...

    await component.close(null);
} finally {
    print("Component destroyed");
}

from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import IReferenceable, IReferences, Descriptor, IUnreferenceable
from pip_services3_commons.run import IOpenable, ICleanable

class MyComponentB():
       
    # ...
    
class MyComponentA(IReferenceable, IUnreferenceable, IConfigurable, IOpenable):
    _param1 = 'ABC'
    _param2 = 123
    _another_component: MyComponentB
    _open = False
    _status = None
    
    # ...
    
    def __del__(self):
        print("Component destroyed")
        
Not available

Important note

In this example, we have created a component that accepts configuration parameters, links to other components, opens and executes a process, closes, deletes the links to other components, and destroys itself.

However, the PIP.services toolkit provides many other components that can be used to add extra functionality, such as connectivity to other services, observability, and other types of persistence.

Final code

The complete code for our example is:

import { 
    ConfigParams, Descriptor, IConfigurable, 
    IOpenable, IReferenceable, IReferences, 
    IUnreferenceable 
} from "pip-services3-commons-nodex";


class MyComponentB implements IConfigurable, IReferenceable, IOpenable, IUnreferenceable {
    private _param1: string = "ABC2";
    private _param2: number = 456;
    private _open: boolean = false;
    private _status: string;

    // Creates a new instance of the component.
    public constructor() {
        this._status = "Created";
        console.log("MyComponentB has been created.");
    }

    public configure(config: ConfigParams): void {
        // pass
    }

    public setReferences(references: IReferences): void {
        // pass
    }

    public isOpen(): boolean {
        // pass
        return true;
    }

    public open(correlationId: string): Promise<void> {
        // pass
        return;
    }

    public close(correlationId: string): Promise<void> {
        // pass
        return;
    }

    public unsetReferences(): void {
        // pass
        return;
    }
}


class MyComponentA implements IConfigurable, IReferenceable, IOpenable, IUnreferenceable {
    private _param1: string = "ABC";
    private _param2: number = 123;
    private _open: boolean = false;
    private _status: string;
    private _anotherComponent: MyComponentB;
    
    public dummyVariable: string;

    // Creates a new instance of the component.
    public constructor(){
        this._status = "Created";
        console.log("MyComponentA has been created.");
    }

    public isOpen(): boolean {
        return this._open;
    }

    public open(correlationId: string): Promise<void> {
        this._open = true;
        this._status = "Open";
        console.log("MyComponentA has been opened.");
        
        return;
    }

    public close(correlationId: string): Promise<void> {
        this._open = false;
        this._status = "Closed";
        console.log("MyComponentA has been closed.");

        return;
    }

    public myTask(correlationId: string): void {
        console.log("Doing my business task");
        this.dummyVariable = "dummy value";
    }

    public setReferences(references: IReferences): void {
        this._anotherComponent = references.getOneRequired<MyComponentB>(
            new Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
        );

        this._status = "Configured";
        console.log("MyComponentA's references have been defined.");
    }

    public unsetReferences(): void {
        this._anotherComponent = null;
        this._status = "Un-referenced";
        console.log("References cleared");
    }

    public configure(config: ConfigParams): void {
        this._param1 = config.getAsStringWithDefault("param1", "ABC");
        this._param2 = config.getAsIntegerWithDefault("param2", 123);
        this._status = "Configured";

        console.log("MyComponentA has been configured.");
    }
}

using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Run;
using System;
using System.Threading.Tasks;

public class MyComponentB: IReferenceable, IUnreferenceable, IConfigurable, IOpenable, IDisposable
{
    private string _param1 = "ABC2";
    private int _param2 = 456;
    private bool _open = false;
    private string _status;

    // Creates a new instance of the component.
    public MyComponentB()
    {
        _status = "Created";
        Console.WriteLine("MyComponentB has been created.");
    }

    public async Task CloseAsync(string correlationId)
    {
        // pass
    }

    public void Configure(ConfigParams config)
    {
        // pass
    }

    public void Dispose()
    {
        // pass
    }

    public bool IsOpen()
    {
        // pass
        return true;
    }

    public async Task OpenAsync(string correlationId)
    {
        // pass
    }

    public void SetReferences(IReferences references)
    {
        // pass
    }

    public void UnsetReferences()
    {
        // pass
    }
}


public class MyComponentA : IReferenceable, IConfigurable, IOpenable, IUnreferenceable, IDisposable
{
    private string _param1 = "ABC";
    private int _param2 = 123;
    private bool _open = false;
    private string _status;
    private MyComponentB _anotherComponent;
        
    public string DummyVariable;

    // Creates a new instance of the component.
    public MyComponentA()
    {
        _status = "Created";
        Console.WriteLine("MyComponentA has been created.");
    }

    public void Configure(ConfigParams config)
    {
        _param1 = config.GetAsStringWithDefault("param1", "ABC");
        _param2 = config.GetAsIntegerWithDefault("param2", 123);
        _status = "Configured";

        Console.WriteLine("MyComponentA has been configured.");
    }

    public bool IsOpen()
    {
        return _open;
    }

    public async Task OpenAsync(string correlationId)
    {
        _open = true;
        _status = "Open";
        Console.WriteLine("MyComponentA has been opened.");
    }

    public async Task CloseAsync(string correlationId)
    {
        _open = false;
        _status = "Closed";
        Console.WriteLine("MyComponentA has been closed.");
    }

    public void MyTask(string correlationId)
    {
        Console.WriteLine("Doing my business task");
        DummyVariable = "dummy value";
    }

    public void SetReferences(IReferences references)
    {
        _anotherComponent = references.GetOneRequired<MyComponentB>(new Descriptor("myservice", "mycomponent-b", "*", "*", "1.0"));

        _status = "Configured";
        Console.WriteLine("MyComponentA's references have been defined.");
    }

    // Unsets (clears) previously set references to dependent components.
    public void UnsetReferences()
    {
        _anotherComponent = null;
        _status = "Un-referenced";
        Console.WriteLine("References cleared");
    }

    public void Dispose()
    {
        Console.WriteLine("Component destroyed");
    }
}

import (
	"fmt"

	config "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
	run "github.com/pip-services3-gox/pip-services3-commons-gox/run"
)

type MyComponentB struct {
	param1 string
	param2 int
	open   bool

	status string
}

// Creates a new instance of the component.
func NewMyComponentB() *MyComponentB {
	fmt.Println("MyComponentB has been created.")

	return &MyComponentB{
		param1: "ABC2",
		param2: 456,
		open:   false,
		status: "Created",
	}
}

func (c *MyComponentB) Configure(ctx context.Context, config *config.ConfigParams) {
	// pass
}

func (c *MyComponentB) SetReferences(ctx context.Context, references refer.IReferences) {
	// pass
}

func (c *MyComponentB) IsOpen() bool {
	// pass
	return true
}

func (c *MyComponentB) Open(ctx context.Context, correlationId string) error {
	// pass
	return nil
}

func (c *MyComponentB) Close(ctx context.Context, correlationId string) error {
	// pass
	return nil
}

// Unsets (clears) previously set references to dependent components.
func (c *MyComponentB) UnsetReferences(ctx context.Context) {
	// pass
}

func (c *MyComponentB) MyTask(ctx context.Context, correlationId string) {
	// pass
}

type MyComponentA struct {
	config.IConfigurable
	refer.IReferenceable
	refer.IUnreferenceable
	run.IOpenable

	param1 string
	param2 int
	open   bool

	anotherComponent interface{}
	dummyVariable    string

	status string
}

// Creates a new instance of the component.
func NewMyComponentA() *MyComponentA {
	fmt.Println("MyComponentA has been created.")

	return &MyComponentA{
		param1: "ABC",
		param2: 123,
		open:   false,
		status: "Created",
	}
}

func (c *MyComponentA) Configure(ctx context.Context, config *config.ConfigParams) {
	c.param1 = config.GetAsStringWithDefault("param1", "ABC")
	c.param2 = config.GetAsIntegerWithDefault("param2", 123)
	c.status = "Configured"
	fmt.Println("MyComponentA has been configured.")
}

func (c *MyComponentA) SetReferences(ctx context.Context, references refer.IReferences) {
	component, err := references.GetOneRequired(
		refer.NewDescriptor("myservice", "mycomponent-b", "*", "*", "1.0"),
	)
	if err == nil {
		c.anotherComponent = component.(*MyComponentB)
		c.status = "Configured"
		fmt.Println("MyComponentA's references have been defined.")
	}

}

func (c *MyComponentA) IsOpen() bool {
	return c.open
}

func (c *MyComponentA) Open(ctx context.Context, correlationId string) error {
	c.open = true
	c.status = "Open"
	fmt.Println("MyComponentA has been opened.")

	return nil
}

func (c *MyComponentA) Close(ctx context.Context, correlationId string) error {
	c.open = false
	c.status = "Closed"
	fmt.Println("MyComponentA has been closed.")

	return nil
}

// Unsets (clears) previously set references to dependent components.
func (c *MyComponentA) UnsetReferences(ctx context.Context) {
	c.anotherComponent = nil
	c.status = "Un-referenced"
	fmt.Println("References cleared")

}

func (c *MyComponentA) MyTask(ctx context.Context, correlationId string) {
	fmt.Println("Doing my business task")
	c.dummyVariable = "dummy value"
}

import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyComponentB
    implements IConfigurable, IReferenceable, IOpenable, IUnreferenceable {
  String _param1 = 'ABC2';
  int _param2 = 456;
  bool _open = false;
  String? _status;

  // Creates a new instance of the component.
  MyComponentB() {
    _status = 'Created';
    print('MyComponentB has been created.');
  }

  @override
  Future close(String? correlationId) async {
    // pass
  }

  @override
  void configure(ConfigParams config) {
    // pass
  }

  @override
  bool isOpen() {
    // pass
    return true;
  }

  @override
  Future open(String? correlationId) async {
    // pass
  }

  @override
  void setReferences(IReferences references) {
    // pass
  }

  @override
  void unsetReferences() {
    // pass
  }
}

class MyComponentA
    implements IConfigurable, IReferenceable, IOpenable, IUnreferenceable {
  String _param1 = 'ABC';
  int _param2 = 123;
  bool _open = false;
  String? _status;
  MyComponentB? _anotherComponent;

  String? dummyVariable;

  // Creates a new instance of the component.
  MyComponentA() {
    _status = 'Created';
    print('MyComponentA has been created.');
  }

  @override
  void setReferences(IReferences references) {
    _anotherComponent = references.getOneRequired<MyComponentB>(
        Descriptor('myservice', 'mycomponent-b', '*', '*', '1.0'));

    _status = 'Configured';
    print("MyComponentA's references have been defined.");
  }

  @override
  void configure(ConfigParams config) {
    _param1 = config.getAsStringWithDefault('param1', 'ABC');
    _param2 = config.getAsIntegerWithDefault('param2', 123);
    _status = 'Configured';

    print('MyComponentA has been configured.');
  }

  @override
  bool isOpen() {
    return _open;
  }

  @override
  Future open(String? correlationId) async {
    _open = true;
    _status = 'Open';
    print('MyComponentA has been opened.');
  }

  @override
  Future close(String? correlationId) async {
    _open = false;
    _status = 'Closed';
    print('MyComponentA has been closed.');
  }

  void myTask(String correlationId) {
    print('Doing my business task');
    dummyVariable = 'dummy value';
  }

  @override
  void unsetReferences() {
    _anotherComponent = null;
    _status = 'Un-referenced';
    print('References cleared');
  }
}

from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import IReferenceable, IReferences, Descriptor, IUnreferenceable
from pip_services3_commons.run import IOpenable

class MyComponentB(IReferenceable, IUnreferenceable, IConfigurable, IOpenable):
    _param1 = 'ABC2'
    _param2 = 456
    _opened = False

    def __init__(self):
        """
        Creates a new instance of the component.
        """
        self._status = "Created"
        print("MyComponentB has been created.")
        
    def configure(self, config):
        self._param1 = config.get_as_string_with_default("param1", self._param1)
        self._param2 = config.get_as_integer_with_default("param2", self._param2)
        print("MyComponentB has been configured.")
        
    def set_references(self, references):
        pass
        
    def is_open(self):
        pass

    def open(self, correlation_id):
        pass

    def close(self, correlation_id):
        pass
        
    def my_task(self, correlation_id):
        pass

    def unset_references(self):
        pass
    
    def __del__(self):
        pass



class MyComponentA(IReferenceable, IUnreferenceable, IConfigurable, IOpenable):
    _param1 = 'ABC'
    _param2 = 123
    _another_component: MyComponentB
    _open = False
    _status = None
    
    def __init__(self):
        """
        Creates a new instance of the component.
        """
        self._status = "Created"
        print("MyComponentA has been created.")
            
    def configure(self, config):
        self._param1 = config.get_as_string_with_default("param1", 'ABC')
        self._param2 = config.get_as_integer_with_default("param2", 123)
        self._status = "Configured"
        print("MyComponentA has been configured.")

    def set_references(self, references):
        self._another_component = references.get_one_required(
            Descriptor("myservice", "mycomponent-b", "*", "*", "1.0")
        )
        self._status = "Configured"
        print("MyComponentA's references have been defined.")
        
    def is_open(self):
        return self._open

    def open(self, correlation_id):
        self._open = True
        self._status = "Open"
        print("MyComponentA has been opened.")

    def close(self, correlation_id):
        self._opened = False
        self._status = "Closed"
        print("MyComponentA has been closed.")
        
    def my_task(self, correlation_id):
        print("Doing my business task")
        dummy_variable = "dummy value"

    def unset_references(self):
        """
        Unsets (clears) previously set references to dependent components.
        """
        self._another_component = None
        self._status = "Un-referenced"
        print("References cleared")
    
    def __del__(self):
        print("Component destroyed")

Not available

Executing our code

Now, we can execute our code step-by-step. Our program will look something like this:

import 'package:pip_services3_commons/pip_services3_commons.dart';

void main(List<String> arguments) async {
  try {
    // Step 1 - Creation
    var myComponentA = MyComponentA();
    var myComponentB = MyComponentB();

    // Step 2 - Configure the component
    myComponentA
        .configure(ConfigParams.fromTuples(['param1', 'XYZ', 'param2', '987']));

    // Step 3 - Referencing
    // Set references to the component
    myComponentA.setReferences(References.fromTuples([
      Descriptor('myservice', 'mycomponent-b', 'default', 'default', '1.0'),
      myComponentB
    ]));

    // Step 4 - Openning
    await myComponentA.open('123');

    // Step 5 - Execution
    myComponentA.myTask('123');

    // Step 6 - Closing
    await myComponentA.close('123');

    // Step 7 - Un-referencing
    myComponentA.unsetReferences();
  } finally {
    // Step 8 - Destruction
    print('Component destroyed');
  }
}
using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;


static void Main(string[] args)
{
    // Step 1 - Creation
    var myComponentA = new MyComponentA();
    var myComponentB = new MyComponentB();

    // Step 2 - Configure the component
    myComponentA.Configure(ConfigParams.FromTuples(
        "param1", "XYZ",
        "param2", "987"
    ));

    // Step 3 - Referencing
    // Set references to the component
    myComponentA.SetReferences(References.FromTuples(
        new Descriptor("myservice", "mycomponent-b", "default", "default", "1.0"), myComponentB
    ));

    // Step 4 - Openning
    myComponentA.OpenAsync("123").Wait();

    // Step 5 - Execution
    myComponentA.MyTask("123");

    // Step 6 - Closing
    myComponentA.CloseAsync("123").Wait();

    // Step 7 - Un-referencing
    myComponentA.UnsetReferences();

    // Step 8 - Destruction
    myComponentA.Dispose();
}

import (
	"fmt"

	config "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
)

func main() {
	// Step 1 - Creation
	myComponentA := NewMyComponentA()
	myComponentB := NewMyComponentB()

	// Step 2 - Configure the component
	myComponentA.Configure(ctx context.Context, config.NewConfigParamsFromTuples(
		"param1", "XYZ",
		"param2", "987",
	))

	// Step 3 - Referencing
	// Set references to the component
	myComponentA.SetReferences(ctx context.Context, refer.NewReferencesFromTuples(
		refer.NewDescriptor("myservice", "mycomponent-b", "default", "default", "1.0"), myComponentB,
	))

	// Step 4 - Openning
	myComponentA.Open(ctx context.Context, "123")

	// Step 5 - Execution
	myComponentA.MyTask(ctx context.Context, "123")

	// Step 6 - Closing
	myComponentA.Close(ctx context.Context, "123")

	// Step 7 - Un-referencing
	myComponentA.UnsetReferences(ctx context.Context)

	// Step 8 - Destruction
	defer func() {
		if !NewMyComponentA().IsOpen() {
			fmt.Println("Component destroyed")
		}
	}()
}

import { 
    ConfigParams, Descriptor, IConfigurable, 
    IOpenable, IReferenceable, IReferences, 
    IUnreferenceable, References
} from "pip-services3-commons-nodex";



async function main() {
    try {
        // Step 1 - Creation
        var myComponentA = new MyComponentA();
        var myComponentB = new MyComponentB();

        // Step 2 - Configure the component
        myComponentA.configure(ConfigParams.fromTuples(
            "param1", "XYZ",
            "param2", "987"
        ));

        // Step 3 - Referencing
        // Set references to the component
        myComponentA.setReferences(References.fromTuples(
            new Descriptor("myservice", "mycomponent-b", "default", "default", "1.0"), myComponentB
        ));

        // Step 4 - Openning
        await myComponentA.open("123");

        // Step 5 - Execution
        myComponentA.myTask("123");

        // Step 6 - Closing
        await myComponentA.close("123");

        // Step 7 - Un-referencing
        myComponentA.unsetReferences();
    } finally {
        // Step 8 - Destruction
        console.log("Component destroyed")
    }
}
from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import References, Descriptor

# Step 1 - Creation
my_component_A = MyComponentA()
my_component_B = MyComponentB()

# Step 2 - Configure the component
my_component_A.configure(ConfigParams.from_tuples(
    'param1', 'XYZ',
    'param2', '987'
))

# Step 3 - Referencing
# Set references to the component
my_component_A.set_references(References.from_tuples(
    Descriptor("myservice", "mycomponent-b", "default", "default", "1.0"), my_component_B
))

# Step 4 - Openning
my_component_A.open("123")

# Step 5 - Execution
my_component_A.my_task("123")

# Step 6 - Closing
my_component_A.close("123")

# Step 7 - Un-referencing
my_component_A.unset_references()

# Step 8 - Destruction
my_component_A.__del__()

Not available

Which, after running, results in the following output:

Console logger messages

Assembling a service from our component

At present, we have a component that is capable of connecting to another component and can execute some actions defined by us. This component is ready for use. However, running it step-by-step can be laborious and inefficient.

To solve this problem, we can use a container. PIP.Services offers the ProcessContainer, which is an Inversion of control (IoC) container that runs as a system process.

As this container uses a factory to create the contained components, we will create one via the Factory class. Once again, we will use Descriptor objects to locate each component, and we will use the method register_as_type to register the component in our factory. This method requires the locator and the component’s type. Our updated code is:

import { Factory } from "pip-services3-components-nodex";

class MyClassFactory extends Factory {
    public constructor() {
        super();

        var ComponentADescriptor = new Descriptor("myservice", "mycomponentA", "default", "*", "1.0");
        var ComponentBDescriptor = new Descriptor("myservice", "mycomponent-b", "default", "*", "1.0");

        this.registerAsType(ComponentADescriptor, MyComponentA);
        this.registerAsType(ComponentBDescriptor, MyComponentB);
    }
}

using PipServices3.Components.Build;

// Creating a factory
public class MyClassFactory: Factory
{
    public MyClassFactory(): base()
    {
        var ComponentADescriptor = new Descriptor("myservice", "mycomponentA", "default", "*", "1.0");
        var ComponentBDescriptor = new Descriptor("myservice", "mycomponent-b", "default", "*", "1.0");
        
        RegisterAsType(ComponentADescriptor, typeof(MyComponentA));
        RegisterAsType(ComponentBDescriptor, typeof(MyComponentB));
    }
}

import (
	build "github.com/pip-services3-gox/pip-services3-components-gox/build"
)

// Creating a factory

type MyClassFactory struct {
	*build.Factory
}

func NewMyClassFactory() *MyClassFactory {
	c := MyClassFactory{}
	c.Factory = build.NewFactory()

	ComponentADescriptor := refer.NewDescriptor("myservice", "mycomponentA", "default", "*", "1.0")
	ComponentBDescriptor := refer.NewDescriptor("myservice", "mycomponent-b", "default", "*", "1.0")

	c.RegisterType(ComponentADescriptor, NewMyComponentA)
	c.RegisterType(ComponentBDescriptor, NewMyComponentB)

	return &c
}

import 'package:pip_services3_components/pip_services3_components.dart';

class MyClassFactory extends Factory {
  MyClassFactory() : super() {
    var ComponentADescriptor =
        Descriptor('myservice', 'mycomponentA', 'default', '*', '1.0');
    var ComponentBDescriptor =
        Descriptor('myservice', 'mycomponent-b', 'default', '*', '1.0');

    registerAsType(ComponentADescriptor, MyComponentA);
    registerAsType(ComponentBDescriptor, MyComponentB);
  }
}

# Creating a factory

from pip_services3_components.build import Factory 

class MyClassFactory(Factory):
    def __init__(self):
        super(MyClassesFactory, self).__init__()

        ComponentADescriptor = Descriptor("myservice", "mycomponentA", "default", "*", "1.0")
        ComponentBDescriptor = Descriptor("myservice", "mycomponent-b", "default", "*", "1.0")

        self.register_as_type(ComponentADescriptor, MyComponentA)
        self.register_as_type(ComponentBDescriptor, MyComponentB)

Not available

Once our factory is ready, we can proceed to create our container. First, we will create a class named MyProcess as a subclass of ProcessContainer. Inside this class, we will state the path to our configuration file, and add our previously created factory.

import { ProcessContainer } from "pip-services3-container-nodex";

// Creating a process container
class MyProcess extends ProcessContainer {
    public constructor() {
        super("myservice", "My service running as a process");

        this._configPath = './config.yaml';
        this._factories.add(new MyClassFactory());
    }
}

using PipServices3.Container;

// Creating a process container
public class MyProcess: ProcessContainer
{
    public MyProcess(): base("myservice", "My service running as a process")
    {
        _configPath = "../../../../config/config.yml";
        _factories.Add(new MyClassFactory());
    }
}

// Creating a process container

type MyProcess struct {
	*container.ProcessContainer
}

func NewMyProcess() *MyProcess {
	c := &MyProcess{
		ProcessContainer: container.NewProcessContainer("myservice", "My service running as a process"),
	}
	c.SetConfigPath("./config.yaml")
	c.AddFactory(NewMyClassFactory())

	return c
}

import 'package:pip_services3_container/pip_services3_container.dart';

// Creating a process container
class MyProcess extends ProcessContainer {
  MyProcess() : super('myservice', 'My service running as a process') {
    configPath = './config.yaml';
    factories.add(MyClassFactory());
  }
}

# Creating a process container

from pip_services3_container import ProcessContainer

class MyProcess(ProcessContainer):
    def __init__(self):
        super(MyProcess, self).__init__('myservice', 'My service running as a process')
        self._config_path = 'E:\\config2.yaml'
        self._factories.add(MyClassFactory())

Not available

Our configuration file must declare our component’s descriptor and the values we want to assign to our parameters. We will use YAML syntax for this purpose. Below is an example of this type of declaration.

Console logger messages

Using our component

We have a service, and to use it, we just need to create an instance of our container and call the run method.

let MyProcess = require('./obj/component').MyProcess;

try {
    let proc = new MyProcess();
    proc.run(process.argv);
} catch (ex) {
    console.error(ex);
}

class Program
{
    static void Main(string[] args)
    {
        try
        {
            var task = (new MyProcess()).RunAsync(args);
            task.Wait();
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex);
        }
    }
}

func main() {
	runner := NewMyProcess()
	runner.Run(os.Environ())
}

void main(List<String> arguments) async {
  try {
    var proc = MyProcess();
    proc.run(arguments);
  } catch (ex) {
    print(ex);
  }
}
if __name__ == '__main__':
    runner = MyProcess()
    print("run")
    try:
        runner.run()
    except Exception as ex:
        print(ex)

Not available

After running our service, we should see the following output, which confirms that components A and B have been created and linked:

Console logger messages

As our component is complete and fully functional, this step marks the end of our task.

Wrapping up

In this tutorial, we have created a component, defined all the necessary methods for managing its lifecycle, and assembled a service from it. We also saw that containers offer a more efficient way to run components.

More complex components will follow a similar structure, but with added functionality. For example, we can add things like different forms of persistence, connectivity to other services, observability, caching, and more. You can find an example of this in the Data Microservice tutorial.