1// Copyright The OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package config
16
17import (
18	"errors"
19	"strings"
20)
21
22// typeAndNameSeparator is the separator that is used between type and name in type/name composite keys.
23const typeAndNameSeparator = "/"
24
25// identifiable is an interface that all components configurations MUST embed.
26type identifiable interface {
27	// ID returns the ID of the component that this configuration belongs to.
28	ID() ComponentID
29	// SetIDName updates the name part of the ID for the component that this configuration belongs to.
30	SetIDName(idName string)
31}
32
33// ComponentID represents the identity for a component. It combines two values:
34// * type - the Type of the component.
35// * name - the name of that component.
36// The component ComponentID (combination type + name) is unique for a given component.Kind.
37type ComponentID struct {
38	typeVal Type   `mapstructure:"-"`
39	nameVal string `mapstructure:"-"`
40}
41
42// NewID returns a new ComponentID with the given Type and empty name.
43func NewID(typeVal Type) ComponentID {
44	return ComponentID{typeVal: typeVal}
45}
46
47// NewIDWithName returns a new ComponentID with the given Type and name.
48func NewIDWithName(typeVal Type, nameVal string) ComponentID {
49	return ComponentID{typeVal: typeVal, nameVal: nameVal}
50}
51
52// NewIDFromString decodes a string in type[/name] format into ComponentID.
53// The type and name components will have spaces trimmed, the "type" part must be present,
54// the forward slash and "name" are optional.
55// The returned ComponentID will be invalid if err is not-nil.
56func NewIDFromString(idStr string) (ComponentID, error) {
57	items := strings.SplitN(idStr, typeAndNameSeparator, 2)
58
59	id := ComponentID{}
60	if len(items) >= 1 {
61		id.typeVal = Type(strings.TrimSpace(items[0]))
62	}
63
64	if len(items) == 0 || id.typeVal == "" {
65		return id, errors.New("idStr must have non empty type")
66	}
67
68	if len(items) > 1 {
69		// "name" part is present.
70		id.nameVal = strings.TrimSpace(items[1])
71		if id.nameVal == "" {
72			return id, errors.New("name part must be specified after " + typeAndNameSeparator + " in type/name key")
73		}
74	}
75
76	return id, nil
77}
78
79// Type returns the type of the component.
80func (id ComponentID) Type() Type {
81	return id.typeVal
82}
83
84// Name returns the custom name of the component.
85func (id ComponentID) Name() string {
86	return id.nameVal
87}
88
89// String returns the ComponentID string representation as "type[/name]" format.
90func (id ComponentID) String() string {
91	if id.nameVal == "" {
92		return string(id.typeVal)
93	}
94
95	return string(id.typeVal) + typeAndNameSeparator + id.nameVal
96}
97