Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / go-openapi / spec / operation.go
1 // Copyright 2015 go-swagger maintainers
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
15 package spec
16
17 import (
18         "bytes"
19         "encoding/gob"
20         "encoding/json"
21         "sort"
22
23         "github.com/go-openapi/jsonpointer"
24         "github.com/go-openapi/swag"
25 )
26
27 func init() {
28         //gob.Register(map[string][]interface{}{})
29         gob.Register(map[string]interface{}{})
30         gob.Register([]interface{}{})
31 }
32
33 // OperationProps describes an operation
34 //
35 // NOTES:
36 // - schemes, when present must be from [http, https, ws, wss]: see validate
37 // - Security is handled as a special case: see MarshalJSON function
38 type OperationProps struct {
39         Description  string                 `json:"description,omitempty"`
40         Consumes     []string               `json:"consumes,omitempty"`
41         Produces     []string               `json:"produces,omitempty"`
42         Schemes      []string               `json:"schemes,omitempty"`
43         Tags         []string               `json:"tags,omitempty"`
44         Summary      string                 `json:"summary,omitempty"`
45         ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
46         ID           string                 `json:"operationId,omitempty"`
47         Deprecated   bool                   `json:"deprecated,omitempty"`
48         Security     []map[string][]string  `json:"security,omitempty"`
49         Parameters   []Parameter            `json:"parameters,omitempty"`
50         Responses    *Responses             `json:"responses,omitempty"`
51 }
52
53 // MarshalJSON takes care of serializing operation properties to JSON
54 //
55 // We use a custom marhaller here to handle a special cases related to
56 // the Security field. We need to preserve zero length slice
57 // while omitting the field when the value is nil/unset.
58 func (op OperationProps) MarshalJSON() ([]byte, error) {
59         type Alias OperationProps
60         if op.Security == nil {
61                 return json.Marshal(&struct {
62                         Security []map[string][]string `json:"security,omitempty"`
63                         *Alias
64                 }{
65                         Security: op.Security,
66                         Alias:    (*Alias)(&op),
67                 })
68         }
69         return json.Marshal(&struct {
70                 Security []map[string][]string `json:"security"`
71                 *Alias
72         }{
73                 Security: op.Security,
74                 Alias:    (*Alias)(&op),
75         })
76 }
77
78 // Operation describes a single API operation on a path.
79 //
80 // For more information: http://goo.gl/8us55a#operationObject
81 type Operation struct {
82         VendorExtensible
83         OperationProps
84 }
85
86 // SuccessResponse gets a success response model
87 func (o *Operation) SuccessResponse() (*Response, int, bool) {
88         if o.Responses == nil {
89                 return nil, 0, false
90         }
91
92         responseCodes := make([]int, 0, len(o.Responses.StatusCodeResponses))
93         for k := range o.Responses.StatusCodeResponses {
94                 if k >= 200 && k < 300 {
95                         responseCodes = append(responseCodes, k)
96                 }
97         }
98         if len(responseCodes) > 0 {
99                 sort.Ints(responseCodes)
100                 v := o.Responses.StatusCodeResponses[responseCodes[0]]
101                 return &v, responseCodes[0], true
102         }
103
104         return o.Responses.Default, 0, false
105 }
106
107 // JSONLookup look up a value by the json property name
108 func (o Operation) JSONLookup(token string) (interface{}, error) {
109         if ex, ok := o.Extensions[token]; ok {
110                 return &ex, nil
111         }
112         r, _, err := jsonpointer.GetForToken(o.OperationProps, token)
113         return r, err
114 }
115
116 // UnmarshalJSON hydrates this items instance with the data from JSON
117 func (o *Operation) UnmarshalJSON(data []byte) error {
118         if err := json.Unmarshal(data, &o.OperationProps); err != nil {
119                 return err
120         }
121         return json.Unmarshal(data, &o.VendorExtensible)
122 }
123
124 // MarshalJSON converts this items object to JSON
125 func (o Operation) MarshalJSON() ([]byte, error) {
126         b1, err := json.Marshal(o.OperationProps)
127         if err != nil {
128                 return nil, err
129         }
130         b2, err := json.Marshal(o.VendorExtensible)
131         if err != nil {
132                 return nil, err
133         }
134         concated := swag.ConcatJSON(b1, b2)
135         return concated, nil
136 }
137
138 // NewOperation creates a new operation instance.
139 // It expects an ID as parameter but not passing an ID is also valid.
140 func NewOperation(id string) *Operation {
141         op := new(Operation)
142         op.ID = id
143         return op
144 }
145
146 // WithID sets the ID property on this operation, allows for chaining.
147 func (o *Operation) WithID(id string) *Operation {
148         o.ID = id
149         return o
150 }
151
152 // WithDescription sets the description on this operation, allows for chaining
153 func (o *Operation) WithDescription(description string) *Operation {
154         o.Description = description
155         return o
156 }
157
158 // WithSummary sets the summary on this operation, allows for chaining
159 func (o *Operation) WithSummary(summary string) *Operation {
160         o.Summary = summary
161         return o
162 }
163
164 // WithExternalDocs sets/removes the external docs for/from this operation.
165 // When you pass empty strings as params the external documents will be removed.
166 // When you pass non-empty string as one value then those values will be used on the external docs object.
167 // So when you pass a non-empty description, you should also pass the url and vice versa.
168 func (o *Operation) WithExternalDocs(description, url string) *Operation {
169         if description == "" && url == "" {
170                 o.ExternalDocs = nil
171                 return o
172         }
173
174         if o.ExternalDocs == nil {
175                 o.ExternalDocs = &ExternalDocumentation{}
176         }
177         o.ExternalDocs.Description = description
178         o.ExternalDocs.URL = url
179         return o
180 }
181
182 // Deprecate marks the operation as deprecated
183 func (o *Operation) Deprecate() *Operation {
184         o.Deprecated = true
185         return o
186 }
187
188 // Undeprecate marks the operation as not deprected
189 func (o *Operation) Undeprecate() *Operation {
190         o.Deprecated = false
191         return o
192 }
193
194 // WithConsumes adds media types for incoming body values
195 func (o *Operation) WithConsumes(mediaTypes ...string) *Operation {
196         o.Consumes = append(o.Consumes, mediaTypes...)
197         return o
198 }
199
200 // WithProduces adds media types for outgoing body values
201 func (o *Operation) WithProduces(mediaTypes ...string) *Operation {
202         o.Produces = append(o.Produces, mediaTypes...)
203         return o
204 }
205
206 // WithTags adds tags for this operation
207 func (o *Operation) WithTags(tags ...string) *Operation {
208         o.Tags = append(o.Tags, tags...)
209         return o
210 }
211
212 // AddParam adds a parameter to this operation, when a parameter for that location
213 // and with that name already exists it will be replaced
214 func (o *Operation) AddParam(param *Parameter) *Operation {
215         if param == nil {
216                 return o
217         }
218
219         for i, p := range o.Parameters {
220                 if p.Name == param.Name && p.In == param.In {
221                         params := append(o.Parameters[:i], *param)
222                         params = append(params, o.Parameters[i+1:]...)
223                         o.Parameters = params
224                         return o
225                 }
226         }
227
228         o.Parameters = append(o.Parameters, *param)
229         return o
230 }
231
232 // RemoveParam removes a parameter from the operation
233 func (o *Operation) RemoveParam(name, in string) *Operation {
234         for i, p := range o.Parameters {
235                 if p.Name == name && p.In == in {
236                         o.Parameters = append(o.Parameters[:i], o.Parameters[i+1:]...)
237                         return o
238                 }
239         }
240         return o
241 }
242
243 // SecuredWith adds a security scope to this operation.
244 func (o *Operation) SecuredWith(name string, scopes ...string) *Operation {
245         o.Security = append(o.Security, map[string][]string{name: scopes})
246         return o
247 }
248
249 // WithDefaultResponse adds a default response to the operation.
250 // Passing a nil value will remove the response
251 func (o *Operation) WithDefaultResponse(response *Response) *Operation {
252         return o.RespondsWith(0, response)
253 }
254
255 // RespondsWith adds a status code response to the operation.
256 // When the code is 0 the value of the response will be used as default response value.
257 // When the value of the response is nil it will be removed from the operation
258 func (o *Operation) RespondsWith(code int, response *Response) *Operation {
259         if o.Responses == nil {
260                 o.Responses = new(Responses)
261         }
262         if code == 0 {
263                 o.Responses.Default = response
264                 return o
265         }
266         if response == nil {
267                 delete(o.Responses.StatusCodeResponses, code)
268                 return o
269         }
270         if o.Responses.StatusCodeResponses == nil {
271                 o.Responses.StatusCodeResponses = make(map[int]Response)
272         }
273         o.Responses.StatusCodeResponses[code] = *response
274         return o
275 }
276
277 type opsAlias OperationProps
278
279 type gobAlias struct {
280         Security []map[string]struct {
281                 List []string
282                 Pad  bool
283         }
284         Alias           *opsAlias
285         SecurityIsEmpty bool
286 }
287
288 // GobEncode provides a safe gob encoder for Operation, including empty security requirements
289 func (o Operation) GobEncode() ([]byte, error) {
290         raw := struct {
291                 Ext   VendorExtensible
292                 Props OperationProps
293         }{
294                 Ext:   o.VendorExtensible,
295                 Props: o.OperationProps,
296         }
297         var b bytes.Buffer
298         err := gob.NewEncoder(&b).Encode(raw)
299         return b.Bytes(), err
300 }
301
302 // GobDecode provides a safe gob decoder for Operation, including empty security requirements
303 func (o *Operation) GobDecode(b []byte) error {
304         var raw struct {
305                 Ext   VendorExtensible
306                 Props OperationProps
307         }
308
309         buf := bytes.NewBuffer(b)
310         err := gob.NewDecoder(buf).Decode(&raw)
311         if err != nil {
312                 return err
313         }
314         o.VendorExtensible = raw.Ext
315         o.OperationProps = raw.Props
316         return nil
317 }
318
319 // GobEncode provides a safe gob encoder for Operation, including empty security requirements
320 func (op OperationProps) GobEncode() ([]byte, error) {
321         raw := gobAlias{
322                 Alias: (*opsAlias)(&op),
323         }
324
325         var b bytes.Buffer
326         if op.Security == nil {
327                 // nil security requirement
328                 err := gob.NewEncoder(&b).Encode(raw)
329                 return b.Bytes(), err
330         }
331
332         if len(op.Security) == 0 {
333                 // empty, but non-nil security requirement
334                 raw.SecurityIsEmpty = true
335                 raw.Alias.Security = nil
336                 err := gob.NewEncoder(&b).Encode(raw)
337                 return b.Bytes(), err
338         }
339
340         raw.Security = make([]map[string]struct {
341                 List []string
342                 Pad  bool
343         }, 0, len(op.Security))
344         for _, req := range op.Security {
345                 v := make(map[string]struct {
346                         List []string
347                         Pad  bool
348                 }, len(req))
349                 for k, val := range req {
350                         v[k] = struct {
351                                 List []string
352                                 Pad  bool
353                         }{
354                                 List: val,
355                         }
356                 }
357                 raw.Security = append(raw.Security, v)
358         }
359
360         err := gob.NewEncoder(&b).Encode(raw)
361         return b.Bytes(), err
362 }
363
364 // GobDecode provides a safe gob decoder for Operation, including empty security requirements
365 func (op *OperationProps) GobDecode(b []byte) error {
366         var raw gobAlias
367
368         buf := bytes.NewBuffer(b)
369         err := gob.NewDecoder(buf).Decode(&raw)
370         if err != nil {
371                 return err
372         }
373         if raw.Alias == nil {
374                 return nil
375         }
376
377         switch {
378         case raw.SecurityIsEmpty:
379                 // empty, but non-nil security requirement
380                 raw.Alias.Security = []map[string][]string{}
381         case len(raw.Alias.Security) == 0:
382                 // nil security requirement
383                 raw.Alias.Security = nil
384         default:
385                 raw.Alias.Security = make([]map[string][]string, 0, len(raw.Security))
386                 for _, req := range raw.Security {
387                         v := make(map[string][]string, len(req))
388                         for k, val := range req {
389                                 v[k] = make([]string, 0, len(val.List))
390                                 v[k] = append(v[k], val.List...)
391                         }
392                         raw.Alias.Security = append(raw.Alias.Security, v)
393                 }
394         }
395
396         *op = *(*OperationProps)(raw.Alias)
397         return nil
398 }