Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / emicklei / go-restful / web_service.go
1 package restful
2
3 import (
4         "errors"
5         "os"
6         "reflect"
7         "sync"
8
9         "github.com/emicklei/go-restful/log"
10 )
11
12 // Copyright 2013 Ernest Micklei. All rights reserved.
13 // Use of this source code is governed by a license
14 // that can be found in the LICENSE file.
15
16 // WebService holds a collection of Route values that bind a Http Method + URL Path to a function.
17 type WebService struct {
18         rootPath       string
19         pathExpr       *pathExpression // cached compilation of rootPath as RegExp
20         routes         []Route
21         produces       []string
22         consumes       []string
23         pathParameters []*Parameter
24         filters        []FilterFunction
25         documentation  string
26         apiVersion     string
27
28         typeNameHandleFunc TypeNameHandleFunction
29
30         dynamicRoutes bool
31
32         // protects 'routes' if dynamic routes are enabled
33         routesLock sync.RWMutex
34 }
35
36 func (w *WebService) SetDynamicRoutes(enable bool) {
37         w.dynamicRoutes = enable
38 }
39
40 // TypeNameHandleFunction declares functions that can handle translating the name of a sample object
41 // into the restful documentation for the service.
42 type TypeNameHandleFunction func(sample interface{}) string
43
44 // TypeNameHandler sets the function that will convert types to strings in the parameter
45 // and model definitions. If not set, the web service will invoke
46 // reflect.TypeOf(object).String().
47 func (w *WebService) TypeNameHandler(handler TypeNameHandleFunction) *WebService {
48         w.typeNameHandleFunc = handler
49         return w
50 }
51
52 // reflectTypeName is the default TypeNameHandleFunction and for a given object
53 // returns the name that Go identifies it with (e.g. "string" or "v1.Object") via
54 // the reflection API.
55 func reflectTypeName(sample interface{}) string {
56         return reflect.TypeOf(sample).String()
57 }
58
59 // compilePathExpression ensures that the path is compiled into a RegEx for those routers that need it.
60 func (w *WebService) compilePathExpression() {
61         compiled, err := newPathExpression(w.rootPath)
62         if err != nil {
63                 log.Printf("invalid path:%s because:%v", w.rootPath, err)
64                 os.Exit(1)
65         }
66         w.pathExpr = compiled
67 }
68
69 // ApiVersion sets the API version for documentation purposes.
70 func (w *WebService) ApiVersion(apiVersion string) *WebService {
71         w.apiVersion = apiVersion
72         return w
73 }
74
75 // Version returns the API version for documentation purposes.
76 func (w *WebService) Version() string { return w.apiVersion }
77
78 // Path specifies the root URL template path of the WebService.
79 // All Routes will be relative to this path.
80 func (w *WebService) Path(root string) *WebService {
81         w.rootPath = root
82         if len(w.rootPath) == 0 {
83                 w.rootPath = "/"
84         }
85         w.compilePathExpression()
86         return w
87 }
88
89 // Param adds a PathParameter to document parameters used in the root path.
90 func (w *WebService) Param(parameter *Parameter) *WebService {
91         if w.pathParameters == nil {
92                 w.pathParameters = []*Parameter{}
93         }
94         w.pathParameters = append(w.pathParameters, parameter)
95         return w
96 }
97
98 // PathParameter creates a new Parameter of kind Path for documentation purposes.
99 // It is initialized as required with string as its DataType.
100 func (w *WebService) PathParameter(name, description string) *Parameter {
101         return PathParameter(name, description)
102 }
103
104 // PathParameter creates a new Parameter of kind Path for documentation purposes.
105 // It is initialized as required with string as its DataType.
106 func PathParameter(name, description string) *Parameter {
107         p := &Parameter{&ParameterData{Name: name, Description: description, Required: true, DataType: "string"}}
108         p.bePath()
109         return p
110 }
111
112 // QueryParameter creates a new Parameter of kind Query for documentation purposes.
113 // It is initialized as not required with string as its DataType.
114 func (w *WebService) QueryParameter(name, description string) *Parameter {
115         return QueryParameter(name, description)
116 }
117
118 // QueryParameter creates a new Parameter of kind Query for documentation purposes.
119 // It is initialized as not required with string as its DataType.
120 func QueryParameter(name, description string) *Parameter {
121         p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string", CollectionFormat: CollectionFormatCSV.String()}}
122         p.beQuery()
123         return p
124 }
125
126 // BodyParameter creates a new Parameter of kind Body for documentation purposes.
127 // It is initialized as required without a DataType.
128 func (w *WebService) BodyParameter(name, description string) *Parameter {
129         return BodyParameter(name, description)
130 }
131
132 // BodyParameter creates a new Parameter of kind Body for documentation purposes.
133 // It is initialized as required without a DataType.
134 func BodyParameter(name, description string) *Parameter {
135         p := &Parameter{&ParameterData{Name: name, Description: description, Required: true}}
136         p.beBody()
137         return p
138 }
139
140 // HeaderParameter creates a new Parameter of kind (Http) Header for documentation purposes.
141 // It is initialized as not required with string as its DataType.
142 func (w *WebService) HeaderParameter(name, description string) *Parameter {
143         return HeaderParameter(name, description)
144 }
145
146 // HeaderParameter creates a new Parameter of kind (Http) Header for documentation purposes.
147 // It is initialized as not required with string as its DataType.
148 func HeaderParameter(name, description string) *Parameter {
149         p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}}
150         p.beHeader()
151         return p
152 }
153
154 // FormParameter creates a new Parameter of kind Form (using application/x-www-form-urlencoded) for documentation purposes.
155 // It is initialized as required with string as its DataType.
156 func (w *WebService) FormParameter(name, description string) *Parameter {
157         return FormParameter(name, description)
158 }
159
160 // FormParameter creates a new Parameter of kind Form (using application/x-www-form-urlencoded) for documentation purposes.
161 // It is initialized as required with string as its DataType.
162 func FormParameter(name, description string) *Parameter {
163         p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}}
164         p.beForm()
165         return p
166 }
167
168 // Route creates a new Route using the RouteBuilder and add to the ordered list of Routes.
169 func (w *WebService) Route(builder *RouteBuilder) *WebService {
170         w.routesLock.Lock()
171         defer w.routesLock.Unlock()
172         builder.copyDefaults(w.produces, w.consumes)
173         w.routes = append(w.routes, builder.Build())
174         return w
175 }
176
177 // RemoveRoute removes the specified route, looks for something that matches 'path' and 'method'
178 func (w *WebService) RemoveRoute(path, method string) error {
179         if !w.dynamicRoutes {
180                 return errors.New("dynamic routes are not enabled.")
181         }
182         w.routesLock.Lock()
183         defer w.routesLock.Unlock()
184         newRoutes := make([]Route, (len(w.routes) - 1))
185         current := 0
186         for ix := range w.routes {
187                 if w.routes[ix].Method == method && w.routes[ix].Path == path {
188                         continue
189                 }
190                 newRoutes[current] = w.routes[ix]
191                 current = current + 1
192         }
193         w.routes = newRoutes
194         return nil
195 }
196
197 // Method creates a new RouteBuilder and initialize its http method
198 func (w *WebService) Method(httpMethod string) *RouteBuilder {
199         return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method(httpMethod)
200 }
201
202 // Produces specifies that this WebService can produce one or more MIME types.
203 // Http requests must have one of these values set for the Accept header.
204 func (w *WebService) Produces(contentTypes ...string) *WebService {
205         w.produces = contentTypes
206         return w
207 }
208
209 // Consumes specifies that this WebService can consume one or more MIME types.
210 // Http requests must have one of these values set for the Content-Type header.
211 func (w *WebService) Consumes(accepts ...string) *WebService {
212         w.consumes = accepts
213         return w
214 }
215
216 // Routes returns the Routes associated with this WebService
217 func (w *WebService) Routes() []Route {
218         if !w.dynamicRoutes {
219                 return w.routes
220         }
221         // Make a copy of the array to prevent concurrency problems
222         w.routesLock.RLock()
223         defer w.routesLock.RUnlock()
224         result := make([]Route, len(w.routes))
225         for ix := range w.routes {
226                 result[ix] = w.routes[ix]
227         }
228         return result
229 }
230
231 // RootPath returns the RootPath associated with this WebService. Default "/"
232 func (w *WebService) RootPath() string {
233         return w.rootPath
234 }
235
236 // PathParameters return the path parameter names for (shared among its Routes)
237 func (w *WebService) PathParameters() []*Parameter {
238         return w.pathParameters
239 }
240
241 // Filter adds a filter function to the chain of filters applicable to all its Routes
242 func (w *WebService) Filter(filter FilterFunction) *WebService {
243         w.filters = append(w.filters, filter)
244         return w
245 }
246
247 // Doc is used to set the documentation of this service.
248 func (w *WebService) Doc(plainText string) *WebService {
249         w.documentation = plainText
250         return w
251 }
252
253 // Documentation returns it.
254 func (w *WebService) Documentation() string {
255         return w.documentation
256 }
257
258 /*
259         Convenience methods
260 */
261
262 // HEAD is a shortcut for .Method("HEAD").Path(subPath)
263 func (w *WebService) HEAD(subPath string) *RouteBuilder {
264         return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("HEAD").Path(subPath)
265 }
266
267 // GET is a shortcut for .Method("GET").Path(subPath)
268 func (w *WebService) GET(subPath string) *RouteBuilder {
269         return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("GET").Path(subPath)
270 }
271
272 // POST is a shortcut for .Method("POST").Path(subPath)
273 func (w *WebService) POST(subPath string) *RouteBuilder {
274         return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("POST").Path(subPath)
275 }
276
277 // PUT is a shortcut for .Method("PUT").Path(subPath)
278 func (w *WebService) PUT(subPath string) *RouteBuilder {
279         return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PUT").Path(subPath)
280 }
281
282 // PATCH is a shortcut for .Method("PATCH").Path(subPath)
283 func (w *WebService) PATCH(subPath string) *RouteBuilder {
284         return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PATCH").Path(subPath)
285 }
286
287 // DELETE is a shortcut for .Method("DELETE").Path(subPath)
288 func (w *WebService) DELETE(subPath string) *RouteBuilder {
289         return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("DELETE").Path(subPath)
290 }