35ae20def502d03a98c7d0d84fc18a55af793755
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019-2021, 2023 Nordix Foundation.
5  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
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  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.apex.service.parameters.carriertechnology;
24
25 import jakarta.ws.rs.core.MultivaluedHashMap;
26 import jakarta.ws.rs.core.MultivaluedMap;
27 import java.util.Arrays;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Set;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33 import java.util.regex.PatternSyntaxException;
34 import lombok.Getter;
35 import lombok.NoArgsConstructor;
36 import lombok.Setter;
37 import org.apache.commons.lang3.StringUtils;
38 import org.onap.policy.common.parameters.BeanValidationResult;
39 import org.onap.policy.common.parameters.ObjectValidationResult;
40 import org.onap.policy.common.parameters.ValidationResult;
41 import org.onap.policy.common.parameters.ValidationStatus;
42 import org.onap.policy.common.utils.validation.ParameterValidationUtils;
43 import org.onap.policy.models.base.Validated;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 // @formatter:off
48 /**
49  * Apex plugin parameters for REST as an event carrier technology with Apex.
50  *
51  * <p>The parameters for this plugin are:
52  * <ol>
53  * <li>url: The URL that the Apex Rest client will connect to over REST for event reception or event sending. This
54  * parameter is mandatory.
55  * <li>httpMethod: The HTTP method to use when sending events over REST, legal values are POST (default) and PUT. When
56  * receiving events, the REST client plugin always uses the HTTP GET method.
57  * <li>httpHeaders, the HTTP headers to send on REST requests, optional parameter, defaults to none.
58  * <li>httpCodeFilter: a regular expression filter for returned HTTP codes, if the returned HTTP code passes this
59  * filter, then the request is assumed to have succeeded by the plugin, optional, defaults to allowing 2xx codes
60  * through, that is a regular expression of "[2][0-9][0-9]"
61  * </ol>
62  *
63  * @author Ning Xi(ning.xi@ericsson.com)
64  */
65 //@formatter:on
66 @Setter
67 @Getter
68 @NoArgsConstructor
69 public class RestPluginCarrierTechnologyParameters extends CarrierTechnologyParameters {
70     // Get a reference to the logger
71     private static final Logger LOGGER = LoggerFactory.getLogger(RestPluginCarrierTechnologyParameters.class);
72
73     /** The supported HTTP methods. */
74     // @formatter:off
75     public enum HttpMethod {
76         GET,
77         PUT,
78         POST,
79         DELETE
80     }
81     // @formatter:on
82
83     /** The default HTTP code filter, allows 2xx HTTP codes through. */
84     public static final String DEFAULT_HTTP_CODE_FILTER = "[2][0-9][0-9]";
85
86     // Commonly occurring strings
87     private static final String HTTP_HEADERS = "httpHeaders";
88     private static final String HTTP_CODE_FILTER = "httpCodeFilter";
89
90     // Regular expression patterns for finding and checking keys in URLs
91     private static final Pattern patternProperKey = Pattern.compile("(?<=\\{)[^}]*(?=\\})");
92     protected static final Pattern patternErrorKey = Pattern
93         .compile("(\\{[^\\{}]*.?\\{)|(\\{[^\\{}]*$)|(\\}[^\\{}]*.?\\})|(^[^\\{}]*.?\\})|\\{\\s*\\}");
94
95     // variable
96     protected String url = null;
97     protected HttpMethod httpMethod = null;
98     protected String[][] httpHeaders = null;
99     protected String httpCodeFilter = DEFAULT_HTTP_CODE_FILTER;
100
101     /**
102      * Check if http headers have been set for the REST request.
103      *
104      * @return true if headers have been set
105      */
106     public boolean checkHttpHeadersSet() {
107         return httpHeaders != null && httpHeaders.length > 0;
108     }
109
110     /**
111      * Gets the http headers for the REST request as a multivalued map.
112      *
113      * @return the headers
114      */
115     public MultivaluedMap<String, Object> getHttpHeadersAsMultivaluedMap() {
116         if (httpHeaders == null) {
117             return null;
118         }
119
120         // Load the HTTP headers into the map
121         MultivaluedMap<String, Object> httpHeaderMap = new MultivaluedHashMap<>();
122
123         for (String[] httpHeader : httpHeaders) {
124             httpHeaderMap.putSingle(httpHeader[0], httpHeader[1]);
125         }
126
127         return httpHeaderMap;
128     }
129
130     /**
131      * Sets the header for the REST request.
132      *
133      * @param httpHeaders the incoming HTTP headers
134      */
135     public void setHttpHeaders(final String[][] httpHeaders) {
136         this.httpHeaders = httpHeaders;
137     }
138
139     /**
140      * Get the tag for the REST Producer Properties.
141      *
142      * @return set of the tags
143      */
144     public Set<String> getKeysFromUrl() {
145         Matcher matcher = patternProperKey.matcher(getUrl());
146         Set<String> key = new HashSet<>();
147         while (matcher.find()) {
148             key.add(matcher.group());
149         }
150         return key;
151     }
152
153     /**
154      * {@inheritDoc}.
155      */
156     @Override
157     public BeanValidationResult validate() {
158         BeanValidationResult result = super.validate();
159
160         result.addResult(validateUrl());
161         result.addResult(validateHttpHeaders());
162         result.addResult(validateHttpCodeFilter());
163
164         return result;
165     }
166
167     // @formatter:off
168     /**
169      * Validate the URL.
170      *
171      * <p/>Checks:
172      * <br/>http://www.blah.com/{par1/somethingelse (Missing end tag) use  {[^\\{}]*$
173      * <br/>http://www.blah.com/{par1/{some}thingelse (Nested tag) use {[^}]*{
174      * <br/>http://www.blah.com/{par1}/some}thingelse (Missing start tag1) use }[^{}]*.}
175      * <br/>http://www.blah.com/par1}/somethingelse (Missing start tag2) use }[^{}]*}
176      * <br/>http://www.blah.com/{}/somethingelse (Empty tag) use {[\s]*}
177      */
178     // @formatter:on
179     public ValidationResult validateUrl() {
180         // The URL may be optional so existence must be checked in the plugin code
181         String url2 = getUrl();
182         if (url2 == null) {
183             return null;
184         }
185
186         var matcher = patternErrorKey.matcher(url2);
187         if (matcher.find()) {
188             final String urlInvalidMessage = "invalid URL has been set for event sending on " + getLabel();
189             return new ObjectValidationResult("url", url2, ValidationStatus.INVALID, urlInvalidMessage);
190         }
191
192         return null;
193     }
194
195     /**
196      * Validate the HTTP headers.
197      *
198      * @return the result of the validation
199      */
200     private ValidationResult validateHttpHeaders() {
201         if (httpHeaders == null) {
202             return null;
203         }
204
205         var result = new BeanValidationResult(HTTP_HEADERS, httpHeaders);
206
207         var item = 0;
208         for (String[] httpHeader : httpHeaders) {
209             final String label = "entry " + (item++);
210             final List<String> value = (httpHeader == null ? null : Arrays.asList(httpHeader));
211             var result2 = new BeanValidationResult(label, value);
212
213             if (httpHeader == null) {
214                 // note: add to result, not result2
215                 result.addResult(label, null, ValidationStatus.INVALID, Validated.IS_NULL);
216
217             } else if (httpHeader.length != 2) {
218                 // note: add to result, not result2
219                 result.addResult(label, value, ValidationStatus.INVALID, "must have one key and one value");
220
221             } else if (!ParameterValidationUtils.validateStringParameter(httpHeader[0])) {
222                 result2.addResult("key", httpHeader[0], ValidationStatus.INVALID, Validated.IS_BLANK);
223
224             } else if (!ParameterValidationUtils.validateStringParameter(httpHeader[1])) {
225                 result2.addResult("value", httpHeader[1], ValidationStatus.INVALID, Validated.IS_BLANK);
226             }
227
228             result.addResult(result2);
229         }
230
231         return result;
232     }
233
234     /**
235      * Validate the HTTP code filter.
236      */
237     public ValidationResult validateHttpCodeFilter() {
238         if (httpCodeFilter == null) {
239             httpCodeFilter = DEFAULT_HTTP_CODE_FILTER;
240
241         } else if (StringUtils.isBlank(httpCodeFilter)) {
242             return new ObjectValidationResult(HTTP_CODE_FILTER, httpCodeFilter, ValidationStatus.INVALID,
243                 "must be a three digit regular expression");
244         } else {
245             try {
246                 Pattern.compile(httpCodeFilter);
247             } catch (PatternSyntaxException pse) {
248                 LOGGER.debug("Invalid HTTP code filter", pse);
249                 String message = "Invalid HTTP code filter, the filter must be specified as a three digit "
250                     + "regular expression: " + pse.getMessage();
251                 return new ObjectValidationResult(HTTP_CODE_FILTER, httpCodeFilter, ValidationStatus.INVALID,
252                                 message);
253             }
254         }
255
256         return null;
257     }
258
259     /**
260      * {@inheritDoc}.
261      */
262     @Override
263     public String toString() {
264         return getLabel() + "CarrierTechnologyParameters [url=" + url + ", httpMethod=" + httpMethod + ", httpHeaders="
265             + Arrays.deepToString(httpHeaders) + ", httpCodeFilter=" + httpCodeFilter + "]";
266     }
267 }