Descriptors
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.
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-services4-components-node";
import (
refer "github.com/pip-services4/pip-services4-go/pip-services4-components-go/refer"
)
from pip_services4_components.refer import Descriptor
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-services4-components-node";
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:*");
}
import (
refer "github.com/pip-services4/pip-services4-go/pip-services4-components-go/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:*")
}
# 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:*")
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-services4-components-node";
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"
}
import (
"fmt"
refer "github.com/pip-services4/pip-services4-go/pip-services4-components-go/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"
}
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"
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-services4-components-node";
export function main() {
let locator1 = new Descriptor("mygroup", "connector", "aws", "default", "1.0");
console.log(locator1.toString());
}
import (
refer "github.com/pip-services4/pip-services4-go/pip-services4-components-go/refer"
)
func main() {
locator1 := refer.NewDescriptor("mygroup", "connector", "aws", "default", "1.0")
locator1.String()
}
locator1 = Descriptor("mygroup", "connector", "aws", "default", "1.0")
locator1.to_string()
![figure 2](figure2.png)
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-services4-components-node";
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
}
import (
refer "github.com/pip-services4/pip-services4-go/pip-services4-components-go/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
}
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
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-services4-components-node";
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
}
import (
refer "github.com/pip-services4/pip-services4-go/pip-services4-components-go/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
}
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
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, Factory } from "pip-services4-components-node";
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");
}
}
import (
"fmt"
build "github.com/pip-services4/pip-services4-go/pip-services4-components-go/build"
refer "github.com/pip-services4/pip-services4-go/pip-services4-components-go/refer"
)
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)
}
from pip_services4_components.build import Factory
from pip_services4_components.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)
![figure 3](figure3.png)
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.