Improve error messages and tests
[nonrtric/plt/sme.git] / capifcore / internal / discoverservice / discoverservice.go
1 // -
2 //   ========================LICENSE_START=================================
3 //   O-RAN-SC
4 //   %%
5 //   Copyright (C) 2022: Nordix Foundation
6 //   %%
7 //   Licensed under the Apache License, Version 2.0 (the "License");
8 //   you may not use this file except in compliance with the License.
9 //   You may obtain a copy of the License at
10 //
11 //        http://www.apache.org/licenses/LICENSE-2.0
12 //
13 //   Unless required by applicable law or agreed to in writing, software
14 //   distributed under the License is distributed on an "AS IS" BASIS,
15 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 //   See the License for the specific language governing permissions and
17 //   limitations under the License.
18 //   ========================LICENSE_END===================================
19 //
20
21 package discoverservice
22
23 import (
24         "fmt"
25         "net/http"
26
27         "oransc.org/nonrtric/capifcore/internal/common29122"
28         discoverapi "oransc.org/nonrtric/capifcore/internal/discoverserviceapi"
29         "oransc.org/nonrtric/capifcore/internal/invokermanagement"
30
31         "github.com/labstack/echo/v4"
32
33         publishapi "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
34 )
35
36 type DiscoverService struct {
37         invokerRegister invokermanagement.InvokerRegister
38 }
39
40 func NewDiscoverService(invokerRegister invokermanagement.InvokerRegister) *DiscoverService {
41         return &DiscoverService{
42                 invokerRegister: invokerRegister,
43         }
44 }
45
46 func (ds *DiscoverService) GetAllServiceAPIs(ctx echo.Context, params discoverapi.GetAllServiceAPIsParams) error {
47         allApis := ds.invokerRegister.GetInvokerApiList(params.ApiInvokerId)
48         if allApis == nil {
49                 return sendCoreError(ctx, http.StatusNotFound, fmt.Sprintf("Invoker %s not registered", params.ApiInvokerId))
50         }
51         filteredApis := []publishapi.ServiceAPIDescription{}
52         gatewayDomain := "r1-expo-func-aef"
53         for _, api := range *allApis {
54                 if !matchesFilter(api, params) {
55                         continue
56                 }
57                 profiles := *api.AefProfiles
58                 for i, profile := range profiles {
59                         profile.DomainName = &gatewayDomain // Hardcoded for now. Should be provided through some other mechanism.
60                         profiles[i] = profile
61                 }
62                 filteredApis = append(filteredApis, api)
63         }
64         discoveredApis := discoverapi.DiscoveredAPIs{
65                 ServiceAPIDescriptions: &filteredApis,
66         }
67         err := ctx.JSON(http.StatusOK, discoveredApis)
68         if err != nil {
69                 // Something really bad happened, tell Echo that our handler failed
70                 return err
71         }
72
73         return nil
74 }
75
76 func matchesFilter(api publishapi.ServiceAPIDescription, filter discoverapi.GetAllServiceAPIsParams) bool {
77         if filter.ApiName != nil && *filter.ApiName != api.ApiName {
78                 return false
79         }
80         if filter.ApiCat != nil && (api.ServiceAPICategory == nil || *filter.ApiCat != *api.ServiceAPICategory) {
81                 return false
82         }
83         profiles := *api.AefProfiles
84         for _, profile := range profiles {
85                 if checkAefId(filter, profile) && checkVersionAndCommType(profile, filter) && checkProtocol(filter, profile) && checkDataFormat(filter, profile) {
86                         return true
87                 }
88         }
89         return false
90 }
91
92 func checkAefId(filter discoverapi.GetAllServiceAPIsParams, profile publishapi.AefProfile) bool {
93         if filter.AefId != nil {
94                 return *filter.AefId == profile.AefId
95         }
96         return true
97 }
98
99 func checkVersionAndCommType(profile publishapi.AefProfile, filter discoverapi.GetAllServiceAPIsParams) bool {
100         match := false
101         if filter.ApiVersion != nil {
102                 for _, version := range profile.Versions {
103                         match = checkVersion(version, filter.ApiVersion, filter.CommType)
104                         if match {
105                                 break
106                         }
107                 }
108         } else if filter.CommType != nil {
109                 for _, version := range profile.Versions {
110                         match = checkCommType(version.Resources, filter.CommType)
111                 }
112         } else {
113                 match = true
114         }
115         return match
116 }
117
118 func checkProtocol(filter discoverapi.GetAllServiceAPIsParams, profile publishapi.AefProfile) bool {
119         if filter.Protocol != nil {
120                 return profile.Protocol != nil && *filter.Protocol == *profile.Protocol
121         }
122         return true
123 }
124
125 func checkDataFormat(filter discoverapi.GetAllServiceAPIsParams, profile publishapi.AefProfile) bool {
126         if filter.DataFormat != nil {
127                 return profile.DataFormat != nil && *filter.DataFormat == *profile.DataFormat
128         }
129         return true
130 }
131
132 func checkVersion(version publishapi.Version, wantedVersion *string, commType *publishapi.CommunicationType) bool {
133         match := false
134         if *wantedVersion == version.ApiVersion {
135                 if commType != nil {
136                         match = checkCommType(version.Resources, commType)
137                 } else {
138                         match = true
139                 }
140         }
141         return match
142 }
143
144 func checkCommType(resources *[]publishapi.Resource, commType *publishapi.CommunicationType) bool {
145         for _, resource := range *resources {
146                 if resource.CommType == *commType {
147                         return true
148                 }
149         }
150         return false
151 }
152
153 // This function wraps sending of an error in the Error format, and
154 // handling the failure to marshal that.
155 func sendCoreError(ctx echo.Context, code int, message string) error {
156         pd := common29122.ProblemDetails{
157                 Cause:  &message,
158                 Status: &code,
159         }
160         err := ctx.JSON(code, pd)
161         return err
162 }