github.com/Axway/agent-sdk@v1.1.101/pkg/apic/provisioning/schemabuilder.go (about) 1 package provisioning 2 3 import ( 4 "encoding/json" 5 "sort" 6 7 "github.com/Axway/agent-sdk/pkg/util/log" 8 ) 9 10 // SchemaBuilder - used to build a subscription schema for API Central 11 type SchemaParser interface { 12 Parse(schemaBytes []byte) (map[string]PropertyDefinition, error) 13 } 14 15 type schemaParser struct { 16 } 17 18 // NewSchemaBuilder - Creates a new subscription schema builder 19 func NewSchemaParser() SchemaParser { 20 return &schemaParser{} 21 } 22 23 // SchemaBuilder - used to build a subscription schema for API Central 24 type SchemaBuilder interface { 25 SetName(name string) SchemaBuilder 26 SetDescription(description string) SchemaBuilder 27 SetPropertyOrder(propertyOrder []string) SchemaBuilder 28 AddProperty(property PropertyBuilder) SchemaBuilder 29 AddUniqueKey(keyName string) SchemaBuilder 30 // Build builds the json schema - this is called automatically by the resource builder 31 Build() (map[string]interface{}, error) 32 } 33 34 // schemaBuilder - holds all the details needs to create a subscription schema 35 type schemaBuilder struct { 36 err error 37 name string 38 description string 39 propertyOrder []string 40 uniqueKeys []string 41 properties map[string]propertyDefinition 42 dependencies map[string]*oneOfPropertyDefinitions 43 schemaVersion string 44 propertyOrderSet bool 45 } 46 47 // jsonSchema - the schema generated from the builder 48 type jsonSchema struct { 49 SubscriptionName string `json:"-"` 50 SchemaType string `json:"type"` 51 SchemaVersion string `json:"$schema"` 52 SchemaDescription string `json:"description"` 53 Properties map[string]propertyDefinition `json:"properties"` 54 Dependencies map[string]*oneOfPropertyDefinitions `json:"dependencies,omitempty"` 55 PropertyOrder []string `json:"x-axway-order,omitempty"` 56 Required []string `json:"required,omitempty"` 57 } 58 59 // NewSchemaBuilder - Creates a new subscription schema builder 60 func NewSchemaBuilder() SchemaBuilder { 61 return &schemaBuilder{ 62 properties: make(map[string]propertyDefinition, 0), 63 dependencies: make(map[string]*oneOfPropertyDefinitions), 64 uniqueKeys: make([]string, 0), 65 propertyOrder: make([]string, 0), 66 propertyOrderSet: false, 67 schemaVersion: "http://json-schema.org/draft-07/schema#", 68 } 69 } 70 71 // SetName - give the subscription schema a name 72 func (s *schemaBuilder) SetName(name string) SchemaBuilder { 73 s.name = name 74 return s 75 } 76 77 // SetDescription - give the subscription schema a description 78 func (s *schemaBuilder) SetDescription(description string) SchemaBuilder { 79 s.description = description 80 return s 81 } 82 83 // SetPropertyOrder - Set a list of ordered fields to be rendered in the UI 84 func (s *schemaBuilder) SetPropertyOrder(propertyOrder []string) SchemaBuilder { 85 // If property names in the property order is bogus, it will be ignored when rendered 86 s.propertyOrder = propertyOrder 87 s.propertyOrderSet = true 88 return s 89 } 90 91 // AddProperty - adds a new subscription schema property to the schema 92 func (s *schemaBuilder) AddProperty(property PropertyBuilder) SchemaBuilder { 93 prop, err := property.Build() 94 if err == nil { 95 s.properties[prop.Name] = *prop 96 97 // If property order wasn't set, add property as they come in 98 if !s.propertyOrderSet { 99 s.propertyOrder = append(s.propertyOrder, prop.Name) 100 } 101 102 dep, err := property.BuildDependencies() 103 if err != nil { 104 s.err = err 105 } 106 if dep != nil { 107 s.dependencies[prop.Name] = dep 108 } 109 } else { 110 s.err = err 111 } 112 113 return s 114 } 115 116 // inList - check to see if the string is in the list. 117 func inList(value string, list []string) bool { 118 for _, v := range list { 119 if v == value { 120 return true 121 } 122 } 123 return false 124 } 125 126 // AddUniqueKey - add a unique key to the schema 127 func (s *schemaBuilder) AddUniqueKey(keyName string) SchemaBuilder { 128 s.uniqueKeys = append(s.uniqueKeys, keyName) 129 return s 130 } 131 132 // Register - build and register the subscription schema 133 func (s *schemaBuilder) Build() (map[string]interface{}, error) { 134 if s.err != nil { 135 return nil, s.err 136 } 137 138 // validate that the property added is in the property order set by the implementation 139 for _, value := range s.properties { 140 if len(s.propertyOrder) > 0 { 141 // if property is not in the set property order, warn 142 if !inList(value.Name, s.propertyOrder) { 143 log.Warnf("property %s is not found in the property order", value.Name) 144 } 145 } 146 } 147 148 // validate that the properties in the property order were added 149 // and that all props in property order are only in once 150 if len(s.propertyOrder) > 0 { 151 newOrder := []string{} 152 props := map[string]struct{}{} 153 for _, orderedProperty := range s.propertyOrder { 154 if _, ok := s.properties[orderedProperty]; !ok { 155 log.Warnf("ordered property %s, was not added as a property", orderedProperty) 156 } 157 158 if _, ok := props[orderedProperty]; !ok { 159 newOrder = append(newOrder, orderedProperty) 160 props[orderedProperty] = struct{}{} 161 } 162 } 163 s.propertyOrder = newOrder 164 } 165 166 // Create the list of required properties 167 required := make([]string, 0) 168 for key, value := range s.properties { 169 if value.Required { 170 required = append(required, key) 171 } 172 } 173 sort.Strings(required) 174 schema := &jsonSchema{ 175 SubscriptionName: s.name, 176 SchemaType: "object", 177 SchemaVersion: s.schemaVersion, 178 SchemaDescription: s.description, 179 Properties: s.properties, 180 Dependencies: s.dependencies, 181 PropertyOrder: s.propertyOrder, 182 Required: required, 183 } 184 185 schemaBytes, err := json.Marshal(schema) 186 if err != nil { 187 return nil, err 188 } 189 schemaMap := map[string]interface{}{} 190 err = json.Unmarshal(schemaBytes, &schemaMap) 191 if err != nil { 192 return nil, err 193 } 194 195 return schemaMap, nil 196 } 197 198 func (s *schemaParser) Parse(schemaBytes []byte) (map[string]PropertyDefinition, error) { 199 schema := &jsonSchema{} 200 err := json.Unmarshal(schemaBytes, schema) 201 if err != nil { 202 return nil, err 203 } 204 205 ret := make(map[string]PropertyDefinition) 206 for s, p := range schema.Properties { 207 buf, _ := json.Marshal(p) 208 newprop := &propertyDefinition{} 209 json.Unmarshal(buf, newprop) 210 ret[s] = newprop 211 } 212 return ret, nil 213 }