cloudfoundry-community/bosh-cloudstack-cpi

View on GitHub
go_agent/src/code.google.com/p/go-charset/charset/local.go

Summary

Maintainability
A
1 hr
Test Coverage
package charset

import (
    "encoding/json"
    "fmt"
    "os"
    "sync"
)

var (
    readLocalCharsetsOnce sync.Once
    localCharsets         = make(map[string]*localCharset)
)

type localCharset struct {
    Charset
    arg string
    *class
}

// A class of character sets.
// Each class can be instantiated with an argument specified in the config file.
// Many character sets can use a single class.
type class struct {
    from, to func(arg string) (Translator, error)
}

// The set of classes, indexed by class name.
var classes = make(map[string]*class)

func registerClass(charset string, from, to func(arg string) (Translator, error)) {
    classes[charset] = &class{from, to}
}

type localFactory struct{}

func (f localFactory) TranslatorFrom(name string) (Translator, error) {
    f.init()
    name = NormalizedName(name)
    cs := localCharsets[name]
    if cs == nil {
        return nil, fmt.Errorf("character set %q not found", name)
    }
    if cs.from == nil {
        return nil, fmt.Errorf("cannot translate from %q", name)
    }
    return cs.from(cs.arg)
}

func (f localFactory) TranslatorTo(name string) (Translator, error) {
    f.init()
    name = NormalizedName(name)
    cs := localCharsets[name]
    if cs == nil {
        return nil, fmt.Errorf("character set %q not found", name)
    }
    if cs.to == nil {
        return nil, fmt.Errorf("cannot translate to %q", name)
    }
    return cs.to(cs.arg)
}

func (f localFactory) Names() []string {
    f.init()
    var names []string
    for name, cs := range localCharsets {
        // add names only for non-aliases.
        if localCharsets[cs.Name] == cs {
            names = append(names, name)
        }
    }
    return names
}

func (f localFactory) Info(name string) *Charset {
    f.init()
    lcs := localCharsets[NormalizedName(name)]
    if lcs == nil {
        return nil
    }
    // copy the charset info so that callers can't mess with it.
    cs := lcs.Charset
    return &cs
}

func (f localFactory) init() {
    readLocalCharsetsOnce.Do(readLocalCharsets)
}

// charsetEntry is the data structure for one entry in the JSON config file.
// If Alias is non-empty, it should be the canonical name of another
// character set; otherwise Class should be the name
// of an entry in classes, and Arg is the argument for
// instantiating it.
type charsetEntry struct {
    Aliases []string
    Desc    string
    Class   string
    Arg     string
}

// readCharsets reads the JSON config file.
// It's done once only, when first needed.
func readLocalCharsets() {
    csdata, err := readFile("charsets.json")
    if err != nil {
        fmt.Fprintf(os.Stderr, "charset: cannot open \"charsets.json\": %v\n", err)
        return
    }

    var entries map[string]charsetEntry
    err = json.Unmarshal(csdata, &entries)
    if err != nil {
        fmt.Fprintf(os.Stderr, "charset: cannot decode config file: %v\n", err)
    }
    for name, e := range entries {
        class := classes[e.Class]
        if class == nil {
            continue
        }
        name = NormalizedName(name)
        for i, a := range e.Aliases {
            e.Aliases[i] = NormalizedName(a)
        }
        cs := &localCharset{
            Charset: Charset{
                Name:    name,
                Aliases: e.Aliases,
                Desc:    e.Desc,
                NoFrom:  class.from == nil,
                NoTo:    class.to == nil,
            },
            arg:   e.Arg,
            class: class,
        }
        localCharsets[cs.Name] = cs
        for _, a := range cs.Aliases {
            localCharsets[a] = cs
        }
    }
}

// A general cache store that local character set translators
// can use for persistent storage of data.
var (
    cacheMutex sync.Mutex
    cacheStore = make(map[interface{}]interface{})
)

func cache(key interface{}, f func() (interface{}, error)) (interface{}, error) {
    cacheMutex.Lock()
    defer cacheMutex.Unlock()
    if x := cacheStore[key]; x != nil {
        return x, nil
    }
    x, err := f()
    if err != nil {
        return nil, err
    }
    cacheStore[key] = x
    return x, err
}