Descriptors

How to locate a component.

Key takeaways

Descriptor A component's locator, which is defined by its group, type, kind, name, and version.
Scenarios Descriptors can define many scenarios such as, for example, a specific component or all persistence components for a certain microservice.

Introduction

This tutorial will help you understand what a descriptor is, how to create one, how to get its properties, how to check its completeness, how to convert it to a string, and how to compare it to other descriptors. Finally, it provides an example of its usage.

What is a Descriptor?

Within the Pip.Services toolkit, a descriptor is a component’s locator that is based on the component’s group, type, kind, name, and version. The Descriptor class is part of the Commons module and is included in the Refer library. The figure below summarizes the different elements of a descriptor.

figure 1

Using Descriptors

a) Pre-requisites

In order to create and use a descriptor, we first need to import this component. This can be done with the following command:

import { Descriptor } from "pip-services3-commons-nodex";

using PipServices3.Commons.Refer;

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

import 'package:pip_services3_commons/pip_services3_commons.dart';

from pip_services3_commons.refer import Descriptor

Not available

b) Creating a descriptor

Descriptors can be created by defining an instance of the Descriptor class. The constructor of this class presents the following structure:

Descriptor(group, type, kind, name, version),

where each field can contain a specific value, *, or None.

Based on this syntax, descriptors allow for the implementation of many different scenarios. Some examples are:

import { Descriptor } from "pip-services3-commons-nodex";

export function main() {
    // Locate all connectors(match by type)
    let locator = Descriptor.fromString("*:connector:*:*:*");

    // Locate all connectors for a specific microservice(match by group and type)
    locator = Descriptor.fromString("mygroup:connector:*:*:*"); 

    // Locate a specific component(match by name)
    locator = Descriptor.fromString("*:*:*:my_name:*");
}

using PipServices3.Commons.Refer;

namespace ExampleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // Locate all connectors (match by type)
            var locator = Descriptor.FromString("*:connector:*:*:*");

            // Locate all connectors for a specific microservice (match by group and type)
            locator = Descriptor.FromString("mygroup:connector:*:*:*");

            // Locate a specific component (match by name)
            locator = Descriptor.FromString("*:*:*:my_name:*");
        }
    }
}


package main

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

func main() {
	// Locate all connectors (match by type)
	locator, _ := refer.ParseDescriptorFromString("*:connector:*:*:*")

	// Locate all connectors for a specific microservice (match by group and type)
	locator, _ = refer.ParseDescriptorFromString("mygroup:connector:*:*:*")

	// Locate a specific component (match by name)
	locator, _ = refer.ParseDescriptorFromString("*:*:*:my_name:*")
}


import 'package:pip_services3_commons/pip_services3_commons.dart';

void main(List<String> arguments) async {
  // Locate all connectors(match by type)
  var locator = Descriptor.fromString('*:connector:*:*:*');

  // Locate all connectors for a specific microservice(match by group and type)
  locator = Descriptor.fromString('mygroup:connector:*:*:*');

  // Locate a specific component(match by name)
  locator = Descriptor.fromString('*:*:*:my_name:*');
}


# Locate all connectors (match by type)
locator = Descriptor.from_string("*:connector:*:*:*") 

# Locate all connectors for a specific microservice (match by group and type)
locator = Descriptor.from_string("mygroup:connector:*:*:*") 

# Locate a specific component (match by name)
locator = Descriptor.from_string("*:*:*:my_name:*") 

Not available

c) Getting its properties

The values of an instance of a descriptor can be obtained via get_xxx() methods, where xxx stands for group, kind, name, or version respectively. The example below shows how to use each of them.

import { Descriptor } from "pip-services3-commons-nodex";

export function main() {
    let locator = new Descriptor("mygroup", "connector", "aws", "default", "1.0");

    console.log(locator.getGroup());   // returns "my_group"
    console.log(locator.getKind());    // returns "aws"
    console.log(locator.getName());    // returns "default"
    console.log(locator.getVersion()); // returns "1.0"
}


using PipServices3.Commons.Refer;
using System;

namespace ExampleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var locator = new Descriptor("mygroup", "connector", "aws", "default", "1.0");

            Console.WriteLine(locator.Group);   // returns "my_group"
            Console.WriteLine(locator.Kind);    // returns "aws"
            Console.WriteLine(locator.Name);    // returns "default"
            Console.WriteLine(locator.Version); // returns "1.0"
        }
    }
}


package main

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

func main() {
	locator := refer.NewDescriptor("mygroup", "connector", "aws", "default", "1.0")

	fmt.Println(locator.Group())   // returns "my_group"
	fmt.Println(locator.Kind())    // returns "aws"
	fmt.Println(locator.Name())    // returns "default"
	fmt.Println(locator.Version()) // returns "1.0"
}


import 'package:pip_services3_commons/pip_services3_commons.dart';

void main(List<String> arguments) async {
  var locator = Descriptor('mygroup', 'connector', 'aws', 'default', '1.0');

  print(locator.getGroup()); // returns "my_group"
  print(locator.getKind()); // returns "aws"
  print(locator.getName()); // returns "default"
  print(locator.getVersion()); // returns "1.0"
}

locator = Descriptor("mygroup", "connector", "aws", "default", "1.0")

locator.get_group()   # returns "my_group"
locator.get_kind()    # returns "aws"
locator.get_name()    # returns "default"
locator.get_version() # returns "1.0"

Not available
d) Converting to string

A string version of a descriptor can be obtained via the to_string() method. The following example explains it.

import { Descriptor } from "pip-services3-commons-nodex";

export function main() {
    let locator1 = new Descriptor("mygroup", "connector", "aws", "default", "1.0");
    console.log(locator1.toString());
}


using PipServices3.Commons.Refer;
using System;

namespace ExampleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var locator1 = new Descriptor("mygroup", "connector", "aws", "default", "1.0");
            Console.WriteLine(locator1.ToString());
        }
    }
}


package main

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

func main() {
	locator1 := refer.NewDescriptor("mygroup", "connector", "aws", "default", "1.0")
	locator1.String()
}


import 'package:pip_services3_commons/pip_services3_commons.dart';

void main(List<String> arguments) async {
  var locator1 = Descriptor('mygroup', 'connector', 'aws', 'default', '1.0');
  print(locator1.toString());
}

locator1 = Descriptor("mygroup", "connector", "aws", "default", "1.0")
locator1.to_string()

Not available
figure 2

e) Checking its completeness

A descriptor is complete when all its fields have a specific value, that is, a value different from * or None. The method is_complete() can be used to check the completeness of a descriptor. It returns true if the descriptor is complete and false otherwise. The example below explains its usage.

import { Descriptor } from "pip-services3-commons-nodex";

export function main() {
    let locator1 = new Descriptor("mygroup", "connector", "aws", "default", "1.0");
    let locator2 = Descriptor.fromString("mygroup:connector:*:*:1.0");

    locator1.isComplete();   // returns True
    locator2.isComplete();   // returns False
}

using PipServices3.Commons.Refer;
using System;

namespace ExampleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var locator1 = new Descriptor("mygroup", "connector", "aws", "default", "1.0");
            var locator2 = Descriptor.FromString("mygroup:connector:*:*:1.0");

            locator1.IsComplete();   // returns True
            locator2.IsComplete();   // returns False
        }
    }
}


package main

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

func main() {
	locator1 := refer.NewDescriptor("mygroup", "connector", "aws", "default", "1.0")
	locator2, _ := refer.ParseDescriptorFromString("mygroup:connector:*:*:1.0")

	locator1.IsComplete() // returns True
	locator2.IsComplete() // returns False
}


import 'package:pip_services3_commons/pip_services3_commons.dart';

void main(List<String> arguments) async {
  var locator1 = Descriptor('mygroup', 'connector', 'aws', 'default', '1.0');
  var locator2 = Descriptor.fromString('mygroup:connector:*:*:1.0');

  locator1.isComplete(); // returns True
  locator2!.isComplete(); // returns False
}


locator1 = Descriptor("mygroup", "connector", "aws", "default", "1.0")
locator2 = Descriptor.from_string("mygroup:connector:*:*:1.0")

locator1.is_complete()   # returns True
locator2.is_complete()   # returns False

Not available

f) Comparing descriptors

There are three matching methods namely match, exact_match and equals. The first partially matches a descriptor to another descriptor. If any field contains * or None, this field will be excluded from the match. The second method matches two descriptors by all fields. Finally, the equals() method compares a descriptor to a value. If the value is a Descriptor, it tries to match them. Otherwise, the method returns false. The following example shows how to use them.

import { Descriptor } from "pip-services3-commons-nodex";

export function main() {
    let locator1 = new Descriptor("mygroup", "connector", "aws", "default", "1.0");
    let locator2 = Descriptor.fromString("mygroup:connector:*:*:1.0");
    let locator3 = Descriptor.fromString("mygroup:connector:aws:default:1.0");

    locator1.match(locator2);       // returns True
    locator1.exactMatch(locator2);  // returns False
    locator1.equals(locator3);      // returns True
}

using PipServices3.Commons.Refer;
using System;

namespace ExampleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var locator1 = new Descriptor("mygroup", "connector", "aws", "default", "1.0");
            var locator2 = Descriptor.FromString("mygroup:connector:*:*:1.0");
            var locator3 = Descriptor.FromString("mygroup:connector:aws:default:1.0");

            locator1.Match(locator2);        // returns True
            locator1.ExactMatch(locator2);  // returns False
            locator1.Equals(locator3);       // returns True
        }
    }
}


package main

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

func main() {
	locator1 := refer.NewDescriptor("mygroup", "connector", "aws", "default", "1.0")
	locator2, _ := refer.ParseDescriptorFromString("mygroup:connector:*:*:1.0")
	locator3, _ := refer.ParseDescriptorFromString("mygroup:connector:aws:default:1.0")

	locator1.Match(locator2)      // returns True
	locator1.ExactMatch(locator2) // returns False
	locator1.Equals(locator3)     // returns True
}


import 'package:pip_services3_commons/pip_services3_commons.dart';

void main(List<String> arguments) async {
  var locator1 = Descriptor('mygroup', 'connector', 'aws', 'default', '1.0');
  var locator2 = Descriptor.fromString('mygroup:connector:*:*:1.0');
  var locator3 = Descriptor.fromString('mygroup:connector:aws:default:1.0');

  locator1.match(locator2!); // returns True
  locator1.exactMatch(locator2); // returns False
  locator1.equals(locator3); // returns True
}


locator1 = Descriptor("mygroup", "connector", "aws", "default", "1.0")
locator2 = Descriptor.from_string("mygroup:connector:*:*:1.0")
locator3 = Descriptor.from_string("mygroup:connector:aws:default:1.0")

locator1.match(locator2)        # returns True
locator1.exact_match(locator2)  # returns False
locator1.equals(locator3)       # returns True

Not available

Example of usage

Now that we know how to handle a descriptor, we will see an example of its application.

Adding a component to a factory

Factories are used to automate component creation. They work by registering components based on their descriptors. In the following example, we first define a custom component, then we register it in a factory previously created, and finally we create an instance of the class. The code is:

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

export function main() {
    let MyFactory1 = new Factory();
    let classADescriptor = new Descriptor("mygroup", "class", "classA", "classA", "1.0");

    MyFactory1.registerAsType(classADescriptor, ClassA);

    MyFactory1.create(classADescriptor);
}

class ClassA{
    public constructor() {
        console.log("ClassA created");
    }
}
using PipServices3.Commons.Refer;
using PipServices3.Components.Build;
using System;

namespace ExampleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var MyFactory1 = new Factory();
            var classADescriptor = new Descriptor("mygroup", "class", "classA", "classA", "1.0");

            MyFactory1.RegisterAsType(classADescriptor, typeof(ClassA));

            MyFactory1.Create(classADescriptor);
        }
    }

    class ClassA
    {
        public ClassA()
        {
            Console.WriteLine("ClassA created");
        }
    }
}

package main

import (
	"fmt"

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

type ComponentA struct{}

func NewComponentA() *ComponentA {
	defer fmt.Println("Created ComponentA")
	return &ComponentA{}
}

func main() {
	MyFactory1 := build.NewFactory()

	myComponentADescriptor := refer.NewDescriptor("mygroup", "class", "classA", "classA", "1.0")

	MyFactory1.RegisterType(myComponentADescriptor, NewComponentA)

	MyFactory1.Create(myComponentADescriptor)
}

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

void main(List<String> arguments) async {
  var MyFactory1 = Factory();
  var classADescriptor =
      Descriptor('mygroup', 'class', 'classA', 'classA', '1.0');

  MyFactory1.registerAsType(classADescriptor, ClassA);

  MyFactory1.create(classADescriptor);
}

class ClassA {
  ClassA() {
    print('ClassA created');
  }
}


from pip_services3_components.build import Factory 
from pip_services3_commons.refer import Descriptor

MyFactory1 = Factory()

class ClassA:   
    
    def __init__(self):
        print("classA created")

classA_descriptor = Descriptor("mygroup", "class", "classA", "classA", "1.0")

MyFactory1.register_as_type(classA_descriptor, ClassA)

MyFactory1.create(classA_descriptor)

Not available
figure 3

Wrapping up

In this tutorial, we have learned that descriptors can be used to define components and groups of components. We have also seen how to obtain a descriptor’s properties, check its completeness, convert it to a string, and compare it to other descriptors. Lastly, we saw an example of their usage by showing how to register a component to a factory.