activity/astool/rdf/referencing.go

213 行
7.9 KiB
Go

package rdf
import (
"fmt"
)
var (
_ Ontology = &ReferenceOntology{}
)
// ReferenceOntology wraps a previously-parsed spec so it can be made known to
// the registry.
type ReferenceOntology struct {
v Vocabulary
}
// SpecURI returns the URI for this specification
func (r *ReferenceOntology) SpecURI() string {
return r.v.URI.String()
}
// Load loads the ontology without an alias.
func (r *ReferenceOntology) Load() ([]RDFNode, error) {
return r.LoadAsAlias("")
}
// LoadAsAlias loads the vocabulary ontology with an alias.
//
// Values cannot be loaded because their serialization and deserialization types
// are not known at runtime if not embedded in the go-fed tool. If the error is
// generated when running the tool, then file a bug so that the tool can
// properly "know" about this particular value and how to serialize and
// deserialize it properly.
func (r *ReferenceOntology) LoadAsAlias(s string) ([]RDFNode, error) {
var nodes []RDFNode
for name, t := range r.v.Types {
nodes = append(nodes, &AliasedDelegate{
Spec: r.v.URI.String(),
Alias: s,
Name: name,
Delegate: &typeReference{t: t, vocabName: r.SpecURI()},
})
}
for name, p := range r.v.Properties {
nodes = append(nodes, &AliasedDelegate{
Spec: r.v.URI.String(),
Alias: s,
Name: name,
Delegate: &propertyReference{p: p, vocabName: r.SpecURI()},
})
}
// Note: Values cannot be added this way as there's no way to detect
// at runtime what the correct serialization and deserialization scheme
// are for particular vocabulary values. Therefore, we omit them here
// and will emit an error.
//
// If this error is emitted, it means a code change to the tool is
// required. A new ontology implementation for this vocabulary needs to
// be added, and a hardcoded implementation of the value's serialization
// and deserialization functions must be created. This will then let the
// rest of the generated code properly serialize and deserialize these
// values.
if len(r.v.Values) > 0 {
return nil, fmt.Errorf("known limitation: value type definitions in a new vocabulary must be embedded in the go-fed tool to ensure that the value is properly serialized and deserialized. This tool is not intelligent enough to automatically somehow deduce what encoding is necessary for new values.")
}
return nodes, nil
}
// LoadSpecificAsAlias loads a specific RDFNode with the given alias.
//
// Values cannot be loaded because their serialization and deserialization types
// are not known at runtime if not embedded in the go-fed tool. If the error is
// generated when running the tool, then file a bug so that the tool can
// properly "know" about this particular value and how to serialize and
// deserialize it properly.
func (r *ReferenceOntology) LoadSpecificAsAlias(alias, name string) ([]RDFNode, error) {
if t, ok := r.v.Types[name]; ok {
return []RDFNode{
&AliasedDelegate{
Spec: "",
Alias: "",
Name: alias,
Delegate: &typeReference{t: t, vocabName: r.SpecURI()},
},
}, nil
}
if p, ok := r.v.Properties[name]; ok {
return []RDFNode{
&AliasedDelegate{
Spec: "",
Alias: "",
Name: alias,
Delegate: &propertyReference{p: p, vocabName: r.SpecURI()},
},
}, nil
}
if _, ok := r.v.Values[name]; ok {
// Note: Values cannot be added this way as there's no way to detect
// at runtime what the correct serialization and deserialization scheme
// are for particular vocabulary values. Therefore, we omit them here
// and will emit an error.
//
// If this error is emitted, it means a code change to the tool is
// required. A new ontology implementation for this vocabulary needs to
// be added, and a hardcoded implementation of the value's serialization
// and deserialization functions must be created. This will then let the
// rest of the generated code properly serialize and deserialize these
// values.
return nil, fmt.Errorf("known limitation: value type definitions in a new vocabulary must be embedded in the go-fed tool to ensure that the value is properly serialized and deserialized. This tool is not intelligent enough to automatically somehow deduce what encoding is necessary for new values.")
}
return nil, fmt.Errorf("ontology (%s) cannot find %q to make alias %q", r.SpecURI(), name, alias)
}
// LoadElement does nothing.
func (r *ReferenceOntology) LoadElement(name string, payload map[string]interface{}) ([]RDFNode, error) {
return nil, nil
}
// GetByName returns a raw, unguarded node by name.
//
// Values cannot be loaded because their serialization and deserialization types
// are not known at runtime if not embedded in the go-fed tool. If the error is
// generated when running the tool, then file a bug so that the tool can
// properly "know" about this particular value and how to serialize and
// deserialize it properly.
func (r *ReferenceOntology) GetByName(name string) (RDFNode, error) {
if t, ok := r.v.Types[name]; ok {
return &typeReference{t: t, vocabName: r.SpecURI()}, nil
}
if p, ok := r.v.Properties[name]; ok {
return &propertyReference{p: p, vocabName: r.SpecURI()}, nil
}
if _, ok := r.v.Values[name]; ok {
// Note: Values cannot be added this way as there's no way to detect
// at runtime what the correct serialization and deserialization scheme
// are for particular vocabulary values. Therefore, we omit them here
// and will emit an error.
//
// If this error is emitted, it means a code change to the tool is
// required. A new ontology implementation for this vocabulary needs to
// be added, and a hardcoded implementation of the value's serialization
// and deserialization functions must be created. This will then let the
// rest of the generated code properly serialize and deserialize these
// values.
return nil, fmt.Errorf("known limitation: value type definitions in a new vocabulary must be embedded in the go-fed tool to ensure that the value is properly serialized and deserialized. This tool is not intelligent enough to automatically somehow deduce what encoding is necessary for new values.")
}
return nil, fmt.Errorf("ontology (%s) cannot find node for name %s", r.SpecURI(), name)
}
var _ RDFNode = &typeReference{}
// typeReference adds a VocabularyReference for a VocabularyType in another
// vocabulary.
type typeReference struct {
t VocabularyType
vocabName string
}
// Enter returns an error.
func (*typeReference) Enter(key string, ctx *ParsingContext) (bool, error) {
return true, fmt.Errorf("typeReference cannot be entered")
}
// Exit returns an error.
func (*typeReference) Exit(key string, ctx *ParsingContext) (bool, error) {
return true, fmt.Errorf("typeReference cannot be exited")
}
// Apply sets a reference in the context.
func (t *typeReference) Apply(key string, value interface{}, ctx *ParsingContext) (bool, error) {
ref, ok := ctx.Current.(*VocabularyReference)
if !ok {
// May be during resolve reference phase -- nothing to do.
return true, nil
}
ref.Name = t.t.GetName()
ref.URI = t.t.URI
ref.Vocab = t.vocabName
return true, nil
}
var _ RDFNode = &propertyReference{}
// typeReference adds a VocabularyReference for a VocabularyProperty in another
// vocabulary.
type propertyReference struct {
p VocabularyProperty
vocabName string
}
// Enter returns an error.
func (*propertyReference) Enter(key string, ctx *ParsingContext) (bool, error) {
return true, fmt.Errorf("propertyReference cannot be entered")
}
// Exit returns an error.
func (*propertyReference) Exit(key string, ctx *ParsingContext) (bool, error) {
return true, fmt.Errorf("propertyReference cannot be exited")
}
// Apply sets a reference in the context.
func (p *propertyReference) Apply(key string, value interface{}, ctx *ParsingContext) (bool, error) {
ref, ok := ctx.Current.(*VocabularyReference)
if !ok {
// May be during resolve reference phase -- nothing to do.
return true, nil
}
ref.Name = p.p.GetName()
ref.URI = p.p.URI
ref.Vocab = p.vocabName
return true, nil
}