diff options
Diffstat (limited to 'plugins/plugins-event/plugins-event-carrier/plugins-event-carrier-restrequestor/src/main')
2 files changed, 151 insertions, 117 deletions
diff --git a/plugins/plugins-event/plugins-event-carrier/plugins-event-carrier-restrequestor/src/main/java/org/onap/policy/apex/plugins/event/carrier/restrequestor/ApexRestRequestorConsumer.java b/plugins/plugins-event/plugins-event-carrier/plugins-event-carrier-restrequestor/src/main/java/org/onap/policy/apex/plugins/event/carrier/restrequestor/ApexRestRequestorConsumer.java index 82d16273f..f60abc24c 100644 --- a/plugins/plugins-event/plugins-event-carrier/plugins-event-carrier-restrequestor/src/main/java/org/onap/policy/apex/plugins/event/carrier/restrequestor/ApexRestRequestorConsumer.java +++ b/plugins/plugins-event/plugins-event-carrier/plugins-event-carrier-restrequestor/src/main/java/org/onap/policy/apex/plugins/event/carrier/restrequestor/ApexRestRequestorConsumer.java @@ -36,11 +36,15 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation.Builder; import javax.ws.rs.core.Response; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.apex.core.infrastructure.threading.ApplicationThreadFactory; import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities; import org.onap.policy.apex.service.engine.event.ApexEventConsumer; @@ -67,6 +71,9 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { // stopped private static final long REST_REQUESTOR_WAIT_SLEEP_TIME = 50; + // The Key for property + private static final String HTTP_CODE_STATUS = "HTTP_CODE_STATUS"; + // The REST parameters read from the parameter service private RestRequestorCarrierTechnologyParameters restConsumerProperties; @@ -104,27 +111,30 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { private String untaggedUrl = null; + // The pattern for filtering status code + private Pattern httpCodeFilterPattern = null; + @Override public void init(final String consumerName, final EventHandlerParameters consumerParameters, - final ApexEventReceiver incomingEventReceiver) throws ApexEventException { + final ApexEventReceiver incomingEventReceiver) throws ApexEventException { this.eventReceiver = incomingEventReceiver; this.name = consumerName; // Check and get the REST Properties if (!(consumerParameters - .getCarrierTechnologyParameters() instanceof RestRequestorCarrierTechnologyParameters)) { - final String errorMessage = "specified consumer properties are not applicable to REST Requestor consumer (" - + this.name + ")"; + .getCarrierTechnologyParameters() instanceof RestRequestorCarrierTechnologyParameters)) { + final String errorMessage = + "specified consumer properties are not applicable to REST Requestor consumer (" + this.name + ")"; LOGGER.warn(errorMessage); throw new ApexEventException(errorMessage); } - restConsumerProperties = (RestRequestorCarrierTechnologyParameters) consumerParameters - .getCarrierTechnologyParameters(); + restConsumerProperties = + (RestRequestorCarrierTechnologyParameters) consumerParameters.getCarrierTechnologyParameters(); // Check if we are in peered mode if (!consumerParameters.isPeeredMode(EventHandlerPeeredMode.REQUESTOR)) { final String errorMessage = "REST Requestor consumer (" + this.name - + ") must run in peered requestor mode with a REST Requestor producer"; + + ") must run in peered requestor mode with a REST Requestor producer"; LOGGER.warn(errorMessage); throw new ApexEventException(errorMessage); } @@ -132,7 +142,7 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { // Check if the HTTP method has been set if (restConsumerProperties.getHttpMethod() == null) { restConsumerProperties - .setHttpMethod(RestRequestorCarrierTechnologyParameters.DEFAULT_REQUESTOR_HTTP_METHOD); + .setHttpMethod(RestRequestorCarrierTechnologyParameters.DEFAULT_REQUESTOR_HTTP_METHOD); } // Check if the HTTP URL has been set @@ -151,6 +161,8 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { throw new ApexEventException(errorMessage, e); } + this.httpCodeFilterPattern = Pattern.compile(restConsumerProperties.getHttpCodeFilter()); + // Set the requestor timeout if (consumerParameters.getPeerTimeout(EventHandlerPeeredMode.REQUESTOR) != 0) { restRequestTimeout = consumerParameters.getPeerTimeout(EventHandlerPeeredMode.REQUESTOR); @@ -159,7 +171,7 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { // Check if HTTP headers has been set if (restConsumerProperties.checkHttpHeadersSet()) { LOGGER.debug("REST Requestor consumer has http headers ({}): {}", this.name, - Arrays.deepToString(restConsumerProperties.getHttpHeaders())); + Arrays.deepToString(restConsumerProperties.getHttpHeaders())); } // Initialize the HTTP client @@ -177,8 +189,8 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { try { incomingRestRequestQueue.add(restRequest); } catch (final Exception requestException) { - final String errorMessage = "could not queue request \"" + restRequest + "\" on REST Requestor consumer (" - + this.name + ")"; + final String errorMessage = + "could not queue request \"" + restRequest + "\" on REST Requestor consumer (" + this.name + ")"; LOGGER.warn(errorMessage, requestException); throw new ApexEventRuntimeException(errorMessage); } @@ -238,8 +250,8 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { while (consumerThread.isAlive() && !stopOrderedFlag) { try { // Take the next event from the queue - final ApexRestRequest restRequest = incomingRestRequestQueue.poll(REST_REQUESTOR_WAIT_SLEEP_TIME, - TimeUnit.MILLISECONDS); + final ApexRestRequest restRequest = + incomingRestRequestQueue.poll(REST_REQUESTOR_WAIT_SLEEP_TIME, TimeUnit.MILLISECONDS); if (restRequest == null) { // Poll timed out, check for request timeouts timeoutExpiredRequests(); @@ -256,8 +268,7 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { op.filter(inputProperty::contains) .orElseThrow(() -> new ApexEventRuntimeException( "key\"" + op.get() + "\"specified on url \"" + restConsumerProperties.getUrl() - + "\"not found in execution properties passed by the current policy")) - ); + + "\"not found in execution properties passed by the current policy"))); untaggedUrl = names.stream().reduce(untaggedUrl, (acc, str) -> acc.replace("{" + str + "}", (String) inputExecutionProperties.get(str))); @@ -301,8 +312,8 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { // Interrupt timed out requests and remove them from the ongoing map for (final ApexRestRequest timedoutRequest : timedoutRequestList) { - final String errorMessage = "REST Requestor consumer (" + this.name + "), REST request timed out: " - + timedoutRequest; + final String errorMessage = + "REST Requestor consumer (" + this.name + "), REST request timed out: " + timedoutRequest; LOGGER.warn(errorMessage); ongoingRestRequestMap.remove(timedoutRequest); @@ -356,12 +367,14 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { // Execute the REST request final Response response = sendEventAsRestRequest(untaggedUrl); - // Check that the event request worked - if (!Response.Status.Family.familyOf(response.getStatus()).equals(Response.Status.Family.SUCCESSFUL)) { - final String errorMessage = "reception of response to \"" + request + "\" from URL \"" - + untaggedUrl + "\" failed with status code " - + response.getStatus() + " and message \"" + response.readEntity(String.class) - + "\""; + // Match the return code + Matcher isPass = httpCodeFilterPattern.matcher(String.valueOf(response.getStatus())); + + // Check that the request worked + if (!isPass.matches()) { + final String errorMessage ="reception of event from URL \"" + restConsumerProperties.getUrl() + + "\" failed with status code " + response.getStatus() + " and message \"" + + response.readEntity(String.class) + "\""; throw new ApexEventRuntimeException(errorMessage); } @@ -369,14 +382,18 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { final String eventJsonString = response.readEntity(String.class); // Check there is content - if (eventJsonString == null || eventJsonString.trim().length() == 0) { - final String errorMessage = "received an enpty response to \"" + request + "\" from URL \"" - + untaggedUrl + "\""; + if (StringUtils.isBlank(eventJsonString)) { + final String errorMessage = + "received an empty response to \"" + request + "\" from URL \"" + untaggedUrl + "\""; throw new ApexEventRuntimeException(errorMessage); } + // build a key and value property in excutionProperties + Properties executionProperties = new Properties(); + executionProperties.put(HTTP_CODE_STATUS, response.getStatus()); + // Send the event into Apex - eventReceiver.receiveEvent(request.getExecutionId(), new Properties(), eventJsonString); + eventReceiver.receiveEvent(request.getExecutionId(), executionProperties, eventJsonString); synchronized (eventsReceivedLock) { eventsReceived++; @@ -403,24 +420,20 @@ public class ApexRestRequestorConsumer implements ApexEventConsumer, Runnable { * @return the response to the REST request */ public Response sendEventAsRestRequest(String untaggedUrl) { + Builder headers = client.target(untaggedUrl).request(APPLICATION_JSON) + .headers(restConsumerProperties.getHttpHeadersAsMultivaluedMap()); switch (restConsumerProperties.getHttpMethod()) { case GET: - return client.target(untaggedUrl).request(APPLICATION_JSON) - .headers(restConsumerProperties.getHttpHeadersAsMultivaluedMap()).get(); + return headers.get(); case PUT: - return client.target(untaggedUrl).request(APPLICATION_JSON) - .headers(restConsumerProperties.getHttpHeadersAsMultivaluedMap()) - .put(Entity.json(request.getEvent())); + return headers.put(Entity.json(request.getEvent())); case POST: - return client.target(untaggedUrl).request(APPLICATION_JSON) - .headers(restConsumerProperties.getHttpHeadersAsMultivaluedMap()) - .post(Entity.json(request.getEvent())); + return headers.post(Entity.json(request.getEvent())); case DELETE: - return client.target(untaggedUrl).request(APPLICATION_JSON) - .headers(restConsumerProperties.getHttpHeadersAsMultivaluedMap()).delete(); + return headers.delete(); default: break; diff --git a/plugins/plugins-event/plugins-event-carrier/plugins-event-carrier-restrequestor/src/main/java/org/onap/policy/apex/plugins/event/carrier/restrequestor/RestRequestorCarrierTechnologyParameters.java b/plugins/plugins-event/plugins-event-carrier/plugins-event-carrier-restrequestor/src/main/java/org/onap/policy/apex/plugins/event/carrier/restrequestor/RestRequestorCarrierTechnologyParameters.java index d583b790e..81aa1a74a 100644 --- a/plugins/plugins-event/plugins-event-carrier/plugins-event-carrier-restrequestor/src/main/java/org/onap/policy/apex/plugins/event/carrier/restrequestor/RestRequestorCarrierTechnologyParameters.java +++ b/plugins/plugins-event/plugins-event-carrier/plugins-event-carrier-restrequestor/src/main/java/org/onap/policy/apex/plugins/event/carrier/restrequestor/RestRequestorCarrierTechnologyParameters.java @@ -26,14 +26,20 @@ import java.util.HashSet; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedMap; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.apex.service.parameters.carriertechnology.CarrierTechnologyParameters; import org.onap.policy.common.parameters.GroupValidationResult; import org.onap.policy.common.parameters.ValidationStatus; import org.onap.policy.common.utils.validation.ParameterValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; // @formatter:off /** @@ -46,14 +52,21 @@ import org.onap.policy.common.utils.validation.ParameterValidationUtils; * This parameter is mandatory. * <li>httpMethod: The HTTP method to use when making requests over REST, legal values are GET (default), * POST, PUT, and DELETE. - * <li>restRequestTimeout: The time in milliseconds to wait for a REST request to complete. - * <li>restRequestHeader: The necessary header needed + * <li>httpHeaders, the HTTP headers to send on REST requests, optional parameter, defaults to none. + * <li>httpCodeFilter: a regular expression filter for returned HTTP codes, if the returned HTTP code passes this + * filter, then the request is assumed to have succeeded by the plugin, optional, defaults to allowing 2xx codes + * through, that is a regular expression of "[2][0-9][0-9]" * </ol> * * @author Liam Fallon (liam.fallon@ericsson.com) */ //@formatter:on +@Getter +@Setter public class RestRequestorCarrierTechnologyParameters extends CarrierTechnologyParameters { + // Get a reference to the logger + private static final Logger LOGGER = LoggerFactory.getLogger(RestRequestorCarrierTechnologyParameters.class); + /** The supported HTTP methods. */ public enum HttpMethod { GET, PUT, POST, DELETE @@ -63,12 +76,12 @@ public class RestRequestorCarrierTechnologyParameters extends CarrierTechnologyP public static final String RESTREQUESTOR_CARRIER_TECHNOLOGY_LABEL = "RESTREQUESTOR"; /** The producer plugin class for the REST carrier technology. */ - public static final String RESTREQUSTOR_EVENT_PRODUCER_PLUGIN_CLASS = ApexRestRequestorProducer.class - .getCanonicalName(); + public static final String RESTREQUSTOR_EVENT_PRODUCER_PLUGIN_CLASS = + ApexRestRequestorProducer.class.getCanonicalName(); /** The consumer plugin class for the REST carrier technology. */ - public static final String RESTREQUSTOR_EVENT_CONSUMER_PLUGIN_CLASS = ApexRestRequestorConsumer.class - .getCanonicalName(); + public static final String RESTREQUSTOR_EVENT_CONSUMER_PLUGIN_CLASS = + ApexRestRequestorConsumer.class.getCanonicalName(); /** The default HTTP method for request events. */ public static final HttpMethod DEFAULT_REQUESTOR_HTTP_METHOD = HttpMethod.GET; @@ -76,20 +89,26 @@ public class RestRequestorCarrierTechnologyParameters extends CarrierTechnologyP /** The default timeout for REST requests. */ public static final long DEFAULT_REST_REQUEST_TIMEOUT = 500; + /** The default HTTP code filter, allows 2xx HTTP codes through. */ + public static final String DEFAULT_HTTP_CODE_FILTER = "[2][0-9][0-9]"; + // Commonly occurring strings private static final String HTTP_HEADERS = "httpHeaders"; + private static final String HTTP_CODE_FILTER = "httpCodeFilter"; + + // Regular expression patterns for finding and checking keys in URLs + private static final Pattern patternProperKey = Pattern.compile("(?<=\\{)[^}]*(?=\\})"); + private static final Pattern patternErrorKey = + Pattern.compile("(\\{[^\\{}]*.?\\{)|(\\{[^\\{}]*$)|(\\}[^\\{}]*.?\\})|(^[^\\{}]*.?\\})|\\{\\s*\\}"); private String url = null; private HttpMethod httpMethod = null; private String[][] httpHeaders = null; - - private static final Pattern patternProperKey = Pattern.compile("(?<=\\{)[^}]*(?=\\})"); - private static final Pattern patternErrorKey = Pattern.compile( - "(\\{[^\\{}]*.?\\{)|(\\{[^\\{}]*$)|(\\}[^\\{}]*.?\\})|(^[^\\{}]*.?\\})|\\{\\s*\\}"); + private String httpCodeFilter = DEFAULT_HTTP_CODE_FILTER; /** - * Constructor to create a REST carrier technology parameters instance and register the instance with the - * parameter service. + * Constructor to create a REST carrier technology parameters instance and register the instance with the parameter + * service. */ public RestRequestorCarrierTechnologyParameters() { super(); @@ -101,42 +120,6 @@ public class RestRequestorCarrierTechnologyParameters extends CarrierTechnologyP } /** - * Gets the URL for the REST request. - * - * @return the URL - */ - public String getUrl() { - return url; - } - - /** - * Sets the URL for the REST request. - * - * @param incomingUrl the URL - */ - public void setUrl(final String incomingUrl) { - this.url = incomingUrl; - } - - /** - * Gets the HTTP method to use for the REST request. - * - * @return the HTTP method - */ - public HttpMethod getHttpMethod() { - return httpMethod; - } - - /** - * Sets the HTTP method to use for the REST request. - * - * @param httpMethod the HTTP method - */ - public void setHttpMethod(final HttpMethod httpMethod) { - this.httpMethod = httpMethod; - } - - /** * Check if http headers have been set for the REST request. * * @return true if headers have beenset @@ -146,15 +129,6 @@ public class RestRequestorCarrierTechnologyParameters extends CarrierTechnologyP } /** - * Gets the http headers for the REST request. - * - * @return the headers - */ - public String[][] getHttpHeaders() { - return httpHeaders; - } - - /** * Gets the http headers for the REST request as a multivalued map. * * @return the headers @@ -189,7 +163,7 @@ public class RestRequestorCarrierTechnologyParameters extends CarrierTechnologyP * @return set of the tags */ public Set<String> getKeysFromUrl() { - Matcher matcher = patternProperKey.matcher(this.url); + Matcher matcher = patternProperKey.matcher(getUrl()); Set<String> key = new HashSet<>(); while (matcher.find()) { key.add(matcher.group()); @@ -197,29 +171,55 @@ public class RestRequestorCarrierTechnologyParameters extends CarrierTechnologyP return key; } + + /** + * {@inheritDoc}. + */ + @Override + public GroupValidationResult validate() { + GroupValidationResult result = super.validate(); + + result = validateUrl(result); + + result = validateHttpHeaders(result); + + return validateHttpCodeFilter(result); + } + + // @formatter:off /** - * Validate tags in url. + * Validate the URL. + * + * <p>Checks: * http://www.blah.com/{par1/somethingelse (Missing end tag) use {[^\\{}]*$ - * http://www.blah.com/{par1/{some}thingelse (Missing end tag2) use {[^}]*{ + * http://www.blah.com/{par1/{some}thingelse (Nested tag) use {[^}]*{ * http://www.blah.com/{par1}/some}thingelse (Missing start tag1) use }[^{}]*.} * http://www.blah.com/par1}/somethingelse (Missing start tag2) use }[^{}]*} * http://www.blah.com/{}/somethingelse (Empty tag) use {[\s]*} - * - * @return if url is legal + * @param result the result of the validation */ - public boolean validateTagInUrl() { - // Check url tag syntax error - Matcher matcher = patternErrorKey.matcher(this.url); - return (!matcher.find()); + // @formatter:on + private GroupValidationResult validateUrl(final GroupValidationResult result) { + // URL is only set on Requestor consumers + if (getUrl() == null) { + return result; + } + + Matcher matcher = patternErrorKey.matcher(getUrl()); + if (matcher.find()) { + result.setResult("url", ValidationStatus.INVALID, + "no proper URL has been set for event sending on REST requestor"); + } + + return result; } /** - * {@inheritDoc}. + * Validate the HTTP headers. + * + * @param result the result of the validation */ - @Override - public GroupValidationResult validate() { - final GroupValidationResult result = super.validate(); - + private GroupValidationResult validateHttpHeaders(final GroupValidationResult result) { if (httpHeaders == null) { return result; } @@ -229,22 +229,43 @@ public class RestRequestorCarrierTechnologyParameters extends CarrierTechnologyP result.setResult(HTTP_HEADERS, ValidationStatus.INVALID, "HTTP header array entry is null"); } else if (httpHeader.length != 2) { result.setResult(HTTP_HEADERS, ValidationStatus.INVALID, - "HTTP header array entries must have one key and one value: " - + Arrays.deepToString(httpHeader)); + "HTTP header array entries must have one key and one value: " + + Arrays.deepToString(httpHeader)); } else if (!ParameterValidationUtils.validateStringParameter(httpHeader[0])) { result.setResult(HTTP_HEADERS, ValidationStatus.INVALID, - "HTTP header key is null or blank: " + Arrays.deepToString(httpHeader)); + "HTTP header key is null or blank: " + Arrays.deepToString(httpHeader)); } else if (!ParameterValidationUtils.validateStringParameter(httpHeader[1])) { result.setResult(HTTP_HEADERS, ValidationStatus.INVALID, - "HTTP header value is null or blank: " + Arrays.deepToString(httpHeader)); + "HTTP header value is null or blank: " + Arrays.deepToString(httpHeader)); } } - if (!validateTagInUrl()) { - result.setResult("url", ValidationStatus.INVALID, - "no proper URL has been set for event sending on REST client"); - } + return result; + } + /** + * Validate the HTTP code filter. + * + * @param result the result of the validation + */ + public GroupValidationResult validateHttpCodeFilter(final GroupValidationResult result) { + if (httpCodeFilter == null) { + httpCodeFilter = DEFAULT_HTTP_CODE_FILTER; + + } else if (StringUtils.isBlank(httpCodeFilter)) { + result.setResult(HTTP_CODE_FILTER, ValidationStatus.INVALID, + "HTTP code filter must be specified as a three digit regular expression"); + } else { + try { + Pattern.compile(httpCodeFilter); + } catch (PatternSyntaxException pse) { + String message = + "Invalid HTTP code filter, the filter must be specified as a three digit regular expression: " + + pse.getMessage(); + result.setResult(HTTP_CODE_FILTER, ValidationStatus.INVALID, message); + LOGGER.debug(message, pse); + } + } return result; } @@ -255,6 +276,6 @@ public class RestRequestorCarrierTechnologyParameters extends CarrierTechnologyP @Override public String toString() { return "RESTRequestorCarrierTechnologyParameters [url=" + url + ", httpMethod=" + httpMethod + ", httpHeaders=" - + Arrays.deepToString(httpHeaders) + "]"; + + Arrays.deepToString(httpHeaders) + ", httpCodeFilter=" + httpCodeFilter + "]"; } } |