Add header missing license header
[ric-plt/resource-status-manager.git] / RSM / controllers / controller.go
1 //
2 // Copyright 2019 AT&T Intellectual Property
3 // Copyright 2019 Nokia
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //      http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16
17 //  This source code is part of the near-RT RIC (RAN Intelligent Controller)
18 //  platform project (RICP).
19
20
21 package controllers
22
23 import (
24         "encoding/json"
25         "io"
26         "io/ioutil"
27         "net/http"
28         "net/http/httputil"
29         "rsm/logger"
30         "rsm/models"
31         "rsm/providers/httpmsghandlerprovider"
32         "rsm/rsmerrors"
33         "strings"
34 )
35
36 const (
37         LimitRequest = 2000
38 )
39
40 type IController interface {
41         ResourceStatus(writer http.ResponseWriter, r *http.Request)
42 }
43
44 type Controller struct {
45         logger          *logger.Logger
46         handlerProvider *httpmsghandlerprovider.RequestHandlerProvider
47 }
48
49 func NewController(logger *logger.Logger, handlerProvider *httpmsghandlerprovider.RequestHandlerProvider) *Controller {
50         return &Controller{
51                 logger:          logger,
52                 handlerProvider: handlerProvider,
53         }
54 }
55
56 func (c *Controller) ResourceStatus(writer http.ResponseWriter, r *http.Request) {
57         c.logger.Infof("[Client -> RSM] #Controller.ResourceStatus - request: %v", c.prettifyRequest(r))
58
59         request := models.ResourceStatusRequest{}
60
61         if !c.extractJsonBody(r, &request, writer) {
62                 return
63         }
64
65         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.ResourceStatusRequest, request, true)
66 }
67
68 func (c *Controller) extractJsonBody(r *http.Request, request models.Request, writer http.ResponseWriter) bool {
69         defer r.Body.Close()
70         body, err := ioutil.ReadAll(io.LimitReader(r.Body, LimitRequest))
71
72         if err != nil {
73                 c.logger.Errorf("[Client -> RSM] #Controller.extractJsonBody - unable to extract json body - error: %s", err)
74                 c.handleErrorResponse(rsmerrors.NewInvalidJsonError(), writer)
75                 return false
76         }
77
78         err = json.Unmarshal(body, &request)
79         if err != nil {
80                 c.logger.Errorf("[Client -> RSM] #Controller.extractJsonBody - unable to extract json body - error: %s", err)
81                 c.handleErrorResponse(rsmerrors.NewInvalidJsonError(), writer)
82                 return false
83         }
84
85         return true
86 }
87
88 func (c *Controller) handleRequest(writer http.ResponseWriter, header *http.Header, requestName httpmsghandlerprovider.IncomingRequest, request models.Request, validateHeader bool) {
89
90         if validateHeader {
91
92                 err := c.validateRequestHeader(header)
93                 if err != nil {
94                         c.handleErrorResponse(err, writer)
95                         return
96                 }
97         }
98
99         handler, err := c.handlerProvider.GetHandler(requestName)
100
101         if err != nil {
102                 c.handleErrorResponse(err, writer)
103                 return
104         }
105
106         err = handler.Handle(request)
107
108         if err != nil {
109                 c.handleErrorResponse(err, writer)
110                 return
111         }
112
113         writer.WriteHeader(http.StatusNoContent)
114         c.logger.Infof("[RSM -> Client] #Controller.handleRequest - status response: %v", http.StatusNoContent)
115 }
116
117 func (c *Controller) validateRequestHeader(header *http.Header) error {
118
119         if header.Get("Content-Type") != "application/json" {
120                 c.logger.Errorf("#Controller.validateRequestHeader - validation failure, incorrect content type")
121
122                 return rsmerrors.NewHeaderValidationError()
123         }
124         return nil
125 }
126
127 func (c *Controller) handleErrorResponse(err error, writer http.ResponseWriter) {
128
129         var errorResponseDetails models.ErrorResponse
130         var httpError int
131
132         if err != nil {
133                 switch err.(type) {
134                 case *rsmerrors.RnibDbError:
135                         e2Error, _ := err.(*rsmerrors.RnibDbError)
136                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
137                         httpError = http.StatusInternalServerError
138                 case *rsmerrors.HeaderValidationError:
139                         e2Error, _ := err.(*rsmerrors.HeaderValidationError)
140                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
141                         httpError = http.StatusUnsupportedMediaType
142                 case *rsmerrors.WrongStateError:
143                         e2Error, _ := err.(*rsmerrors.WrongStateError)
144                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
145                         httpError = http.StatusBadRequest
146                 case *rsmerrors.RequestValidationError:
147                         e2Error, _ := err.(*rsmerrors.RequestValidationError)
148                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
149                         httpError = http.StatusBadRequest
150                 case *rsmerrors.InvalidJsonError:
151                         e2Error, _ := err.(*rsmerrors.InvalidJsonError)
152                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
153                         httpError = http.StatusBadRequest
154                 case *rsmerrors.RmrError:
155                         e2Error, _ := err.(*rsmerrors.RmrError)
156                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
157                         httpError = http.StatusInternalServerError
158                 case *rsmerrors.RsmError:
159                         e2Error, _ := err.(*rsmerrors.RsmError)
160                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
161                         httpError = http.StatusInternalServerError
162                 case *rsmerrors.ResourceNotFoundError:
163                         e2Error, _ := err.(*rsmerrors.ResourceNotFoundError)
164                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
165                         httpError = http.StatusNotFound
166
167                 default:
168                         e2Error := rsmerrors.NewInternalError()
169                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
170                         httpError = http.StatusInternalServerError
171                 }
172         }
173         errorResponse, _ := json.Marshal(errorResponseDetails)
174
175         c.logger.Errorf("[RSM -> Client] #Controller.handleErrorResponse - http status: %d, error response: %+v", httpError, errorResponseDetails)
176
177         writer.Header().Set("Content-Type", "application/json")
178         writer.WriteHeader(httpError)
179         _, err = writer.Write(errorResponse)
180
181         if err != nil {
182                 c.logger.Errorf("#Controller.handleErrorResponse - Cannot send response. writer:%v", writer)
183         }
184 }
185 func (c *Controller) prettifyRequest(request *http.Request) string {
186         dump, _ := httputil.DumpRequest(request, true)
187         requestPrettyPrint := strings.Replace(string(dump), "\r\n", " ", -1)
188         return strings.Replace(requestPrettyPrint, "\n", "", -1)
189 }