~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/utils/registry/registry.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2014 Canonical Ltd.
 
2
// Licensed under the LGPLv3, see LICENCE file for details.
 
3
 
 
4
package registry
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        "reflect"
 
9
        "sort"
 
10
 
 
11
        "github.com/juju/errors"
 
12
)
 
13
 
 
14
// TypedNameVersion is a registry that will allow you to register objects based
 
15
// on a name and version pair. The objects must be convertible to the Type
 
16
// defined when the registry was created. It will be cast during Register so
 
17
// you can be sure all objects returned from Get() are safe to TypeAssert to
 
18
// that type.
 
19
type TypedNameVersion struct {
 
20
        requiredType reflect.Type
 
21
        versions     map[string]Versions
 
22
}
 
23
 
 
24
// NewTypedNameVersion creates a place to register your objects
 
25
func NewTypedNameVersion(requiredType reflect.Type) *TypedNameVersion {
 
26
        return &TypedNameVersion{
 
27
                requiredType: requiredType,
 
28
                versions:     make(map[string]Versions),
 
29
        }
 
30
}
 
31
 
 
32
// Description gives the name and available versions in a registry.
 
33
type Description struct {
 
34
        Name     string
 
35
        Versions []int
 
36
}
 
37
 
 
38
// Versions maps concrete versions of the objects.
 
39
type Versions map[int]interface{}
 
40
 
 
41
// Register records the factory that can be used to produce an instance of the
 
42
// facade at the supplied version.
 
43
// If the object being registered doesn't Implement the required Type, then an
 
44
// error is returned.
 
45
// An error is also returned if an object is already registered with the given
 
46
// name and version.
 
47
func (r *TypedNameVersion) Register(name string, version int, obj interface{}) error {
 
48
        if !reflect.TypeOf(obj).ConvertibleTo(r.requiredType) {
 
49
                return fmt.Errorf("object of type %T cannot be converted to type %s.%s", obj, r.requiredType.PkgPath(), r.requiredType.Name())
 
50
        }
 
51
        obj = reflect.ValueOf(obj).Convert(r.requiredType).Interface()
 
52
        if r.versions == nil {
 
53
                r.versions = make(map[string]Versions, 1)
 
54
        }
 
55
        if versions, ok := r.versions[name]; ok {
 
56
                if _, ok := versions[version]; ok {
 
57
                        fullname := fmt.Sprintf("%s(%d)", name, version)
 
58
                        return fmt.Errorf("object %q already registered", fullname)
 
59
                }
 
60
                versions[version] = obj
 
61
        } else {
 
62
                r.versions[name] = Versions{version: obj}
 
63
        }
 
64
        return nil
 
65
}
 
66
 
 
67
// descriptionFromVersions aggregates the information in a Versions map into a
 
68
// more friendly form for List()
 
69
func descriptionFromVersions(name string, versions Versions) Description {
 
70
        intVersions := make([]int, 0, len(versions))
 
71
        for version := range versions {
 
72
                intVersions = append(intVersions, version)
 
73
        }
 
74
        sort.Ints(intVersions)
 
75
        return Description{
 
76
                Name:     name,
 
77
                Versions: intVersions,
 
78
        }
 
79
}
 
80
 
 
81
// List returns a slice describing each of the registered Facades.
 
82
func (r *TypedNameVersion) List() []Description {
 
83
        names := make([]string, 0, len(r.versions))
 
84
        for name := range r.versions {
 
85
                names = append(names, name)
 
86
        }
 
87
        sort.Strings(names)
 
88
        descriptions := make([]Description, len(r.versions))
 
89
        for i, name := range names {
 
90
                versions := r.versions[name]
 
91
                descriptions[i] = descriptionFromVersions(name, versions)
 
92
        }
 
93
        return descriptions
 
94
}
 
95
 
 
96
// Get returns the object for a single name and version. If the requested
 
97
// facade is not found, it returns error.NotFound
 
98
func (r *TypedNameVersion) Get(name string, version int) (interface{}, error) {
 
99
        if versions, ok := r.versions[name]; ok {
 
100
                if factory, ok := versions[version]; ok {
 
101
                        return factory, nil
 
102
                }
 
103
        }
 
104
        return nil, errors.NotFoundf("%s(%d)", name, version)
 
105
}