Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / emicklei / go-restful / entity_accessors.go
1 package restful
2
3 // Copyright 2015 Ernest Micklei. All rights reserved.
4 // Use of this source code is governed by a license
5 // that can be found in the LICENSE file.
6
7 import (
8         "encoding/xml"
9         "strings"
10         "sync"
11 )
12
13 // EntityReaderWriter can read and write values using an encoding such as JSON,XML.
14 type EntityReaderWriter interface {
15         // Read a serialized version of the value from the request.
16         // The Request may have a decompressing reader. Depends on Content-Encoding.
17         Read(req *Request, v interface{}) error
18
19         // Write a serialized version of the value on the response.
20         // The Response may have a compressing writer. Depends on Accept-Encoding.
21         // status should be a valid Http Status code
22         Write(resp *Response, status int, v interface{}) error
23 }
24
25 // entityAccessRegistry is a singleton
26 var entityAccessRegistry = &entityReaderWriters{
27         protection: new(sync.RWMutex),
28         accessors:  map[string]EntityReaderWriter{},
29 }
30
31 // entityReaderWriters associates MIME to an EntityReaderWriter
32 type entityReaderWriters struct {
33         protection *sync.RWMutex
34         accessors  map[string]EntityReaderWriter
35 }
36
37 func init() {
38         RegisterEntityAccessor(MIME_JSON, NewEntityAccessorJSON(MIME_JSON))
39         RegisterEntityAccessor(MIME_XML, NewEntityAccessorXML(MIME_XML))
40 }
41
42 // RegisterEntityAccessor add/overrides the ReaderWriter for encoding content with this MIME type.
43 func RegisterEntityAccessor(mime string, erw EntityReaderWriter) {
44         entityAccessRegistry.protection.Lock()
45         defer entityAccessRegistry.protection.Unlock()
46         entityAccessRegistry.accessors[mime] = erw
47 }
48
49 // NewEntityAccessorJSON returns a new EntityReaderWriter for accessing JSON content.
50 // This package is already initialized with such an accessor using the MIME_JSON contentType.
51 func NewEntityAccessorJSON(contentType string) EntityReaderWriter {
52         return entityJSONAccess{ContentType: contentType}
53 }
54
55 // NewEntityAccessorXML returns a new EntityReaderWriter for accessing XML content.
56 // This package is already initialized with such an accessor using the MIME_XML contentType.
57 func NewEntityAccessorXML(contentType string) EntityReaderWriter {
58         return entityXMLAccess{ContentType: contentType}
59 }
60
61 // accessorAt returns the registered ReaderWriter for this MIME type.
62 func (r *entityReaderWriters) accessorAt(mime string) (EntityReaderWriter, bool) {
63         r.protection.RLock()
64         defer r.protection.RUnlock()
65         er, ok := r.accessors[mime]
66         if !ok {
67                 // retry with reverse lookup
68                 // more expensive but we are in an exceptional situation anyway
69                 for k, v := range r.accessors {
70                         if strings.Contains(mime, k) {
71                                 return v, true
72                         }
73                 }
74         }
75         return er, ok
76 }
77
78 // entityXMLAccess is a EntityReaderWriter for XML encoding
79 type entityXMLAccess struct {
80         // This is used for setting the Content-Type header when writing
81         ContentType string
82 }
83
84 // Read unmarshalls the value from XML
85 func (e entityXMLAccess) Read(req *Request, v interface{}) error {
86         return xml.NewDecoder(req.Request.Body).Decode(v)
87 }
88
89 // Write marshalls the value to JSON and set the Content-Type Header.
90 func (e entityXMLAccess) Write(resp *Response, status int, v interface{}) error {
91         return writeXML(resp, status, e.ContentType, v)
92 }
93
94 // writeXML marshalls the value to JSON and set the Content-Type Header.
95 func writeXML(resp *Response, status int, contentType string, v interface{}) error {
96         if v == nil {
97                 resp.WriteHeader(status)
98                 // do not write a nil representation
99                 return nil
100         }
101         if resp.prettyPrint {
102                 // pretty output must be created and written explicitly
103                 output, err := xml.MarshalIndent(v, " ", " ")
104                 if err != nil {
105                         return err
106                 }
107                 resp.Header().Set(HEADER_ContentType, contentType)
108                 resp.WriteHeader(status)
109                 _, err = resp.Write([]byte(xml.Header))
110                 if err != nil {
111                         return err
112                 }
113                 _, err = resp.Write(output)
114                 return err
115         }
116         // not-so-pretty
117         resp.Header().Set(HEADER_ContentType, contentType)
118         resp.WriteHeader(status)
119         return xml.NewEncoder(resp).Encode(v)
120 }
121
122 // entityJSONAccess is a EntityReaderWriter for JSON encoding
123 type entityJSONAccess struct {
124         // This is used for setting the Content-Type header when writing
125         ContentType string
126 }
127
128 // Read unmarshalls the value from JSON
129 func (e entityJSONAccess) Read(req *Request, v interface{}) error {
130         decoder := NewDecoder(req.Request.Body)
131         decoder.UseNumber()
132         return decoder.Decode(v)
133 }
134
135 // Write marshalls the value to JSON and set the Content-Type Header.
136 func (e entityJSONAccess) Write(resp *Response, status int, v interface{}) error {
137         return writeJSON(resp, status, e.ContentType, v)
138 }
139
140 // write marshalls the value to JSON and set the Content-Type Header.
141 func writeJSON(resp *Response, status int, contentType string, v interface{}) error {
142         if v == nil {
143                 resp.WriteHeader(status)
144                 // do not write a nil representation
145                 return nil
146         }
147         if resp.prettyPrint {
148                 // pretty output must be created and written explicitly
149                 output, err := MarshalIndent(v, "", " ")
150                 if err != nil {
151                         return err
152                 }
153                 resp.Header().Set(HEADER_ContentType, contentType)
154                 resp.WriteHeader(status)
155                 _, err = resp.Write(output)
156                 return err
157         }
158         // not-so-pretty
159         resp.Header().Set(HEADER_ContentType, contentType)
160         resp.WriteHeader(status)
161         return NewEncoder(resp).Encode(v)
162 }