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