rest api call node target entity
[ccsdk/sli/plugins.git] / restapi-call-node / provider / src / main / java / org / onap / ccsdk / sli / plugins / restapicall / RestapiCallNode.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                      reserved.
7  * Modifications Copyright © 2018 IBM.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.ccsdk.sli.plugins.restapicall;
24
25 import static java.lang.Boolean.valueOf;
26 import static javax.ws.rs.client.Entity.entity;
27 import static org.onap.ccsdk.sli.plugins.restapicall.AuthType.fromString;
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.io.IOException;
31 import java.net.SocketException;
32 import java.net.URI;
33 import java.nio.file.Files;
34 import java.nio.file.Paths;
35 import java.security.KeyStore;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Map.Entry;
44 import java.util.Properties;
45 import java.util.Set;
46 import javax.net.ssl.HttpsURLConnection;
47 import javax.net.ssl.KeyManagerFactory;
48 import javax.net.ssl.SSLContext;
49 import javax.ws.rs.ProcessingException;
50 import javax.ws.rs.client.Client;
51 import javax.ws.rs.client.ClientBuilder;
52 import javax.ws.rs.client.Entity;
53 import javax.ws.rs.client.Invocation;
54 import javax.ws.rs.client.WebTarget;
55 import javax.ws.rs.core.EntityTag;
56 import javax.ws.rs.core.Feature;
57 import javax.ws.rs.core.MediaType;
58 import javax.ws.rs.core.MultivaluedMap;
59 import javax.ws.rs.core.Response;
60 import javax.ws.rs.core.UriBuilder;
61 import org.apache.commons.lang3.StringUtils;
62 import org.codehaus.jettison.json.JSONException;
63 import org.codehaus.jettison.json.JSONObject;
64 import org.glassfish.jersey.client.ClientProperties;
65 import org.glassfish.jersey.client.HttpUrlConnectorProvider;
66 import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
67 import org.glassfish.jersey.client.oauth1.ConsumerCredentials;
68 import org.glassfish.jersey.client.oauth1.OAuth1ClientSupport;
69 import org.glassfish.jersey.media.multipart.MultiPart;
70 import org.glassfish.jersey.media.multipart.MultiPartFeature;
71 import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
72 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
73 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
74 import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
75 import org.onap.logging.filter.base.MetricLogClientFilter;
76 import org.onap.logging.ref.slf4j.ONAPLogConstants;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
79 import org.slf4j.MDC;
80
81 public class RestapiCallNode implements SvcLogicJavaPlugin {
82
83     protected static final String PARTNERS_FILE_NAME = "partners.json";
84     protected static final String UEB_PROPERTIES_FILE_NAME = "ueb.properties";
85     protected static final String DEFAULT_PROPERTIES_DIR = "/opt/onap/ccsdk/data/properties";
86     protected static final String PROPERTIES_DIR_KEY = "SDNC_CONFIG_DIR";
87     protected static final int DEFAULT_HTTP_CONNECT_TIMEOUT_MS = 30000; // 30 seconds
88     protected static final int DEFAULT_HTTP_READ_TIMEOUT_MS = 600000; // 10 minutes
89
90     private static final Logger log = LoggerFactory.getLogger(RestapiCallNode.class);
91     private String uebServers;
92     private String defaultUebTemplateFileName = "/opt/bvc/restapi/templates/default-ueb-message.json";
93
94     private String responseReceivedMessage = "Response received. Time: {}";
95     private String responseHttpCodeMessage = "HTTP response code: {}";
96     private String requestPostingException = "Exception while posting http request to client ";
97     protected static final String skipSendingMessage = "skipSending";
98     protected static final String responsePrefix = "responsePrefix";
99     protected static final String restapiUrlString = "restapiUrl";
100     protected static final String restapiUserKey = "restapiUser";
101     protected static final String restapiPasswordKey = "restapiPassword";
102     protected Integer httpConnectTimeout;
103     protected Integer httpReadTimeout;
104
105     protected HashMap<String, PartnerDetails> partnerStore;
106
107     public RestapiCallNode() {
108         String configDir = System.getProperty(PROPERTIES_DIR_KEY, DEFAULT_PROPERTIES_DIR);
109         try {
110             String jsonString = readFile(configDir + "/" + PARTNERS_FILE_NAME);
111             JSONObject partners = new JSONObject(jsonString);
112             partnerStore = new HashMap<>();
113             loadPartners(partners);
114             log.info("Partners support enabled");
115         } catch (Exception e) {
116             log.warn("Partners file could not be read, Partner support will not be enabled.", e);
117         }
118
119         try (FileInputStream in = new FileInputStream(configDir + "/" + UEB_PROPERTIES_FILE_NAME)) {
120             Properties props = new Properties();
121             props.load(in);
122             uebServers = props.getProperty("servers");
123             log.info("UEB support enabled");
124         } catch (Exception e) {
125             log.warn("UEB properties could not be read, UEB support will not be enabled.", e);
126         }
127         httpConnectTimeout = readOptionalInteger("HTTP_CONNECT_TIMEOUT_MS",DEFAULT_HTTP_CONNECT_TIMEOUT_MS);
128         httpReadTimeout = readOptionalInteger("HTTP_READ_TIMEOUT_MS",DEFAULT_HTTP_READ_TIMEOUT_MS);
129     }
130
131     protected void loadPartners(JSONObject partners) {
132         Iterator<String> keys = partners.keys();
133         String partnerUserKey = "user";
134         String partnerPasswordKey = "password";
135         String partnerUrlKey = "url";
136
137         while (keys.hasNext()) {
138             String partnerKey = keys.next();
139             try {
140                 JSONObject partnerObject = (JSONObject) partners.get(partnerKey);
141                 if (partnerObject.has(partnerUserKey) && partnerObject.has(partnerPasswordKey)) {
142                     String url = null;
143                     if (partnerObject.has(partnerUrlKey)) {
144                         url = partnerObject.getString(partnerUrlKey);
145                     }
146                     String userName = partnerObject.getString(partnerUserKey);
147                     String password = partnerObject.getString(partnerPasswordKey);
148                     PartnerDetails details = new PartnerDetails(userName, getObfuscatedVal(password), url);
149                     partnerStore.put(partnerKey, details);
150                     log.info("mapped partner using partner key " + partnerKey);
151                 } else {
152                     log.info("Partner " + partnerKey + " is missing required keys, it won't be mapped");
153                 }
154             } catch (JSONException e) {
155                 log.info("Couldn't map the partner using partner key " + partnerKey, e);
156             }
157         }
158     }
159
160     /* Unobfuscate param value */
161     private static String getObfuscatedVal(String paramValue) {
162         String resValue = paramValue;
163         if (paramValue != null && paramValue.startsWith("${") && paramValue.endsWith("}"))
164         {
165             String paramStr = paramValue.substring(2, paramValue.length()-1);
166             if (paramStr  != null && paramStr.length() > 0)
167             {
168                 String val = System.getenv(paramStr);
169                 if (val != null && val.length() > 0)
170                 {
171                     resValue=val;
172                     log.info("Obfuscated value RESET for param value:" + paramValue);
173                 }
174             }
175         }
176         return resValue;
177     }
178
179     /**
180      * Returns parameters from the parameter map.
181      *
182      * @param paramMap parameter map
183      * @param p parameters instance
184      * @return parameters filed instance
185      * @throws SvcLogicException when svc logic exception occurs
186      */
187     public static Parameters getParameters(Map<String, String> paramMap, Parameters p) throws SvcLogicException {
188
189         p.templateFileName = parseParam(paramMap, "templateFileName", false, null);
190         p.requestBody = parseParam(paramMap, "requestBody", false, null);
191         p.restapiUrl = parseParam(paramMap, restapiUrlString, true, null);
192         p.restapiUrlSuffix = parseParam(paramMap, "restapiUrlSuffix", false, null);
193         if (p.restapiUrlSuffix != null) {
194             p.restapiUrl = p.restapiUrl + p.restapiUrlSuffix;
195         }
196
197         p.restapiUrl = UriBuilder.fromUri(p.restapiUrl).toTemplate();
198         validateUrl(p.restapiUrl);
199
200         p.restapiUser = parseParam(paramMap, restapiUserKey, false, null);
201         p.restapiPassword = parseParam(paramMap, restapiPasswordKey, false, null);
202         p.oAuthConsumerKey = parseParam(paramMap, "oAuthConsumerKey", false, null);
203         p.oAuthConsumerSecret = parseParam(paramMap, "oAuthConsumerSecret", false, null);
204         p.oAuthSignatureMethod = parseParam(paramMap, "oAuthSignatureMethod", false, null);
205         p.oAuthVersion = parseParam(paramMap, "oAuthVersion", false, null);
206         p.contentType = parseParam(paramMap, "contentType", false, null);
207         p.format = Format.fromString(parseParam(paramMap, "format", false, "json"));
208         p.authtype = fromString(parseParam(paramMap, "authType", false, "unspecified"));
209         p.httpMethod = HttpMethod.fromString(parseParam(paramMap, "httpMethod", false, "post"));
210         p.responsePrefix = parseParam(paramMap, responsePrefix, false, null);
211         p.listNameList = getListNameList(paramMap);
212         String skipSendingStr = paramMap.get(skipSendingMessage);
213         p.skipSending = "true".equalsIgnoreCase(skipSendingStr);
214         p.convertResponse = valueOf(parseParam(paramMap, "convertResponse", false, "true"));
215         p.trustStoreFileName = parseParam(paramMap, "trustStoreFileName", false, null);
216         p.trustStorePassword = parseParam(paramMap, "trustStorePassword", false, null);
217         p.keyStoreFileName = parseParam(paramMap, "keyStoreFileName", false, null);
218         p.keyStorePassword = parseParam(paramMap, "keyStorePassword", false, null);
219         p.ssl = p.trustStoreFileName != null && p.trustStorePassword != null && p.keyStoreFileName != null
220             && p.keyStorePassword != null;
221         p.customHttpHeaders = parseParam(paramMap, "customHttpHeaders", false, null);
222         p.partner = parseParam(paramMap, "partner", false, null);
223         p.dumpHeaders = valueOf(parseParam(paramMap, "dumpHeaders", false, null));
224         p.returnRequestPayload = valueOf(parseParam(paramMap, "returnRequestPayload", false, null));
225         p.accept = parseParam(paramMap, "accept", false, null);
226         p.multipartFormData = valueOf(parseParam(paramMap, "multipartFormData", false, "false"));
227         p.multipartFile = parseParam(paramMap, "multipartFile", false, null);
228         p.targetEntity = parseParam(paramMap, "targetEntity", false, null);
229         return p;
230     }
231
232     /**
233      * Validates the given URL in the parameters.
234      *
235      * @param restapiUrl rest api URL
236      * @throws SvcLogicException when URL validation fails
237      */
238     private static void validateUrl(String restapiUrl) throws SvcLogicException {
239         if (restapiUrl.contains(",")) {
240             String[] urls = restapiUrl.split(",");
241             for (String url : urls) {
242                 validateUrl(url);
243             }
244         } else {
245             try {
246                 URI.create(restapiUrl);
247             } catch (IllegalArgumentException e) {
248                 throw new SvcLogicException("Invalid input of url " + e.getLocalizedMessage(), e);
249             }
250         }
251     }
252
253     /**
254      * Returns the list of list name.
255      *
256      * @param paramMap parameters map
257      * @return list of list name
258      */
259     private static Set<String> getListNameList(Map<String, String> paramMap) {
260         Set<String> ll = new HashSet<>();
261         for (Map.Entry<String, String> entry : paramMap.entrySet()) {
262             if (entry.getKey().startsWith("listName")) {
263                 ll.add(entry.getValue());
264             }
265         }
266         return ll;
267     }
268
269     /**
270      * Parses the parameter string map of property, validates if required, assigns default value if
271      * present and returns the value.
272      *
273      * @param paramMap string param map
274      * @param name name of the property
275      * @param required if value required
276      * @param def default value
277      * @return value of the property
278      * @throws SvcLogicException if required parameter value is empty
279      */
280     public static String parseParam(Map<String, String> paramMap, String name, boolean required, String def)
281         throws SvcLogicException {
282         String s = paramMap.get(name);
283
284         if (s == null || s.trim().length() == 0) {
285             if (!required) {
286                 return def;
287             }
288             throw new SvcLogicException("Parameter " + name + " is required in RestapiCallNode");
289         }
290
291         s = s.trim();
292         StringBuilder value = new StringBuilder();
293         int i = 0;
294         int i1 = s.indexOf('%');
295         while (i1 >= 0) {
296             int i2 = s.indexOf('%', i1 + 1);
297             if (i2 < 0) {
298                 break;
299             }
300
301             String varName = s.substring(i1 + 1, i2);
302             String varValue = System.getenv(varName);
303             if (varValue == null) {
304                 varValue = "%" + varName + "%";
305             }
306
307             value.append(s.substring(i, i1));
308             value.append(varValue);
309
310             i = i2 + 1;
311             i1 = s.indexOf('%', i);
312         }
313         value.append(s.substring(i));
314
315         log.info("Parameter {}: [{}]", name, maskPassword(name, value));
316
317         return value.toString();
318     }
319
320     private static Object maskPassword(String name, Object value) {
321         String[] pwdNames = {"pwd", "passwd", "password", "Pwd", "Passwd", "Password"};
322         for (String pwdName : pwdNames) {
323             if (name.contains(pwdName)) {
324                 return "**********";
325             }
326         }
327         return value;
328     }
329
330     /**
331      * Allows Directed Graphs the ability to interact with REST APIs.
332      *
333      * @param paramMap HashMap<String,String> of parameters passed by the DG to this function
334      *        <table border="1">
335      *        <thead>
336      *        <th>parameter</th>
337      *        <th>Mandatory/Optional</th>
338      *        <th>description</th>
339      *        <th>example values</th></thead> <tbody>
340      *        <tr>
341      *        <td>templateFileName</td>
342      *        <td>Optional</td>
343      *        <td>full path to template file that can be used to build a request</td>
344      *        <td>/sdncopt/bvc/restapi/templates/vnf_service-configuration-operation_minimal.json</td>
345      *        </tr>
346      *        <tr>
347      *        <td>restapiUrl</td>
348      *        <td>Mandatory</td>
349      *        <td>url to send the request to</td>
350      *        <td>https://sdncodl:8543/restconf/operations/L3VNF-API:create-update-vnf-request</td>
351      *        </tr>
352      *        <tr>
353      *        <td>restapiUser</td>
354      *        <td>Optional</td>
355      *        <td>user name to use for http basic authentication</td>
356      *        <td>sdnc_ws</td>
357      *        </tr>
358      *        <tr>
359      *        <td>restapiPassword</td>
360      *        <td>Optional</td>
361      *        <td>unencrypted password to use for http basic authentication</td>
362      *        <td>plain_password</td>
363      *        </tr>
364      *        <tr>
365      *        <td>oAuthConsumerKey</td>
366      *        <td>Optional</td>
367      *        <td>Consumer key to use for http oAuth authentication</td>
368      *        <td>plain_key</td>
369      *        </tr>
370      *        <tr>
371      *        <td>oAuthConsumerSecret</td>
372      *        <td>Optional</td>
373      *        <td>Consumer secret to use for http oAuth authentication</td>
374      *        <td>plain_secret</td>
375      *        </tr>
376      *        <tr>
377      *        <td>oAuthSignatureMethod</td>
378      *        <td>Optional</td>
379      *        <td>Consumer method to use for http oAuth authentication</td>
380      *        <td>method</td>
381      *        </tr>
382      *        <tr>
383      *        <td>oAuthVersion</td>
384      *        <td>Optional</td>
385      *        <td>Version http oAuth authentication</td>
386      *        <td>version</td>
387      *        </tr>
388      *        <tr>
389      *        <td>contentType</td>
390      *        <td>Optional</td>
391      *        <td>http content type to set in the http header</td>
392      *        <td>usually application/json or application/xml</td>
393      *        </tr>
394      *        <tr>
395      *        <td>format</td>
396      *        <td>Optional</td>
397      *        <td>should match request body format</td>
398      *        <td>json or xml</td>
399      *        </tr>
400      *        <tr>
401      *        <td>httpMethod</td>
402      *        <td>Optional</td>
403      *        <td>http method to use when sending the request</td>
404      *        <td>get post put delete patch</td>
405      *        </tr>
406      *        <tr>
407      *        <td>responsePrefix</td>
408      *        <td>Optional</td>
409      *        <td>location the response will be written to in context memory</td>
410      *        <td>tmp.restapi.result</td>
411      *        </tr>
412      *        <tr>
413      *        <td>listName[i]</td>
414      *        <td>Optional</td>
415      *        <td>Used for processing XML responses with repeating
416      *        elements.</td>vpn-information.vrf-details
417      *        <td></td>
418      *        </tr>
419      *        <tr>
420      *        <td>skipSending</td>
421      *        <td>Optional</td>
422      *        <td></td>
423      *        <td>true or false</td>
424      *        </tr>
425      *        <tr>
426      *        <td>convertResponse</td>
427      *        <td>Optional</td>
428      *        <td>whether the response should be converted</td>
429      *        <td>true or false</td>
430      *        </tr>
431      *        <tr>
432      *        <td>customHttpHeaders</td>
433      *        <td>Optional</td>
434      *        <td>a list additional http headers to be passed in, follow the format in the example</td>
435      *        <td>X-CSI-MessageId=messageId,headerFieldName=headerFieldValue</td>
436      *        </tr>
437      *        <tr>
438      *        <td>dumpHeaders</td>
439      *        <td>Optional</td>
440      *        <td>when true writes http header content to context memory</td>
441      *        <td>true or false</td>
442      *        </tr>
443      *        <tr>
444      *        <td>partner</td>
445      *        <td>Optional</td>
446      *        <td>used to retrieve username, password and url if partner store exists</td>
447      *        <td>aaf</td>
448      *        </tr>
449      *        <tr>
450      *        <td>returnRequestPayload</td>
451      *        <td>Optional</td>
452      *        <td>used to return payload built in the request</td>
453      *        <td>true or false</td>
454      *        </tr>
455      *        </tbody>
456      *        </table>
457      * @param ctx Reference to context memory
458      * @throws SvcLogicException
459      * @since 11.0.2
460      * @see String#split(String, int)
461      */
462     public void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException {
463         sendRequest(paramMap, ctx, null);
464     }
465
466     protected void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx, RetryPolicy retryPolicy)
467         throws SvcLogicException {
468
469         HttpResponse r = new HttpResponse();
470         try {
471             handlePartner(paramMap);
472             Parameters p = getParameters(paramMap, new Parameters());
473             if(p.targetEntity != null && !p.targetEntity.isEmpty()) {
474                 MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, p.targetEntity);
475             }
476             if (p.restapiUrl.contains(",") && retryPolicy == null) {
477                 String[] urls = p.restapiUrl.split(",");
478                 retryPolicy = new RetryPolicy(urls, urls.length * 2);
479                 p.restapiUrl = urls[0];
480             }
481             String pp = p.responsePrefix != null ? p.responsePrefix + '.' : "";
482
483             String req = null;
484             if (p.templateFileName != null) {
485                 String reqTemplate = readFile(p.templateFileName);
486                 req = buildXmlJsonRequest(ctx, reqTemplate, p.format);
487             } else if (p.requestBody != null) {
488                 req = p.requestBody;
489             }
490             r = sendHttpRequest(req, p);
491             setResponseStatus(ctx, p.responsePrefix, r);
492
493             if (p.dumpHeaders && r.headers != null) {
494                 for (Entry<String, List<String>> a : r.headers.entrySet()) {
495                     ctx.setAttribute(pp + "header." + a.getKey(), StringUtils.join(a.getValue(), ","));
496                 }
497             }
498
499             if (p.returnRequestPayload && req != null) {
500                 ctx.setAttribute(pp + "httpRequest", req);
501             }
502
503             if (r.body != null && r.body.trim().length() > 0) {
504                 ctx.setAttribute(pp + "httpResponse", r.body);
505
506                 if (p.convertResponse) {
507                     Map<String, String> mm = null;
508                     if (p.format == Format.XML) {
509                         mm = XmlParser.convertToProperties(r.body, p.listNameList);
510                     } else if (p.format == Format.JSON) {
511                         mm = JsonParser.convertToProperties(r.body);
512                     }
513
514                     if (mm != null) {
515                         for (Map.Entry<String, String> entry : mm.entrySet()) {
516                             ctx.setAttribute(pp + entry.getKey(), entry.getValue());
517                         }
518                     }
519                 }
520             }
521         } catch (SvcLogicException e) {
522             boolean shouldRetry = false;
523             if (e.getCause().getCause() instanceof SocketException) {
524                 shouldRetry = true;
525             }
526
527             log.error("Error sending the request: " + e.getMessage(), e);
528             String prefix = parseParam(paramMap, responsePrefix, false, null);
529             if (retryPolicy == null || !shouldRetry) {
530                 setFailureResponseStatus(ctx, prefix, e.getMessage(), r);
531             } else {
532                 log.debug(retryPolicy.getRetryMessage());
533                 try {
534                     // calling getNextHostName increments the retry count so it should be called before shouldRetry
535                     String retryString = retryPolicy.getNextHostName();
536                     if (retryPolicy.shouldRetry()) {
537                         paramMap.put(restapiUrlString, retryString);
538                         log.debug("retry attempt {} will use the retry url {}", retryPolicy.getRetryCount(),
539                             retryString);
540                         sendRequest(paramMap, ctx, retryPolicy);
541                     } else {
542                         log.debug("Maximum retries reached, won't attempt to retry. Calling setFailureResponseStatus.");
543                         setFailureResponseStatus(ctx, prefix, e.getMessage(), r);
544                     }
545                 } catch (Exception ex) {
546                     String retryErrorMessage = "Retry attempt " + retryPolicy.getRetryCount()
547                         + "has failed with error message " + ex.getMessage();
548                     setFailureResponseStatus(ctx, prefix, retryErrorMessage, r);
549                 }
550             }
551         }
552
553         if (r != null && r.code >= 300) {
554             throw new SvcLogicException(String.valueOf(r.code) + ": " + r.message);
555         }
556     }
557
558     protected void handlePartner(Map<String, String> paramMap) {
559         String partner = paramMap.get("partner");
560         if (partner != null && partner.length() > 0) {
561             PartnerDetails details = partnerStore.get(partner);
562             paramMap.put(restapiUserKey, details.username);
563             paramMap.put(restapiPasswordKey, details.password);
564             if (paramMap.get(restapiUrlString) == null) {
565                 paramMap.put(restapiUrlString, details.url);
566             }
567         }
568     }
569
570     protected String buildXmlJsonRequest(SvcLogicContext ctx, String template, Format format) throws SvcLogicException {
571         log.info("Building {} started", format);
572         long t1 = System.currentTimeMillis();
573         String originalTemplate = template;
574
575         template = expandRepeats(ctx, template, 1);
576
577         Map<String, String> mm = new HashMap<>();
578         for (String s : ctx.getAttributeKeySet()) {
579             mm.put(s, ctx.getAttribute(s));
580         }
581
582         StringBuilder ss = new StringBuilder();
583         int i = 0;
584         while (i < template.length()) {
585             int i1 = template.indexOf("${", i);
586             if (i1 < 0) {
587                 ss.append(template.substring(i));
588                 break;
589             }
590
591             int i2 = template.indexOf('}', i1 + 2);
592             if (i2 < 0) {
593                 throw new SvcLogicException("Template error: Matching } not found");
594             }
595
596             String var1 = template.substring(i1 + 2, i2);
597             String value1 = format == Format.XML ? XmlJsonUtil.getXml(mm, var1) : XmlJsonUtil.getJson(mm, var1);
598             if (value1 == null || value1.trim().length() == 0) {
599                 // delete the whole element (line)
600                 int i3 = template.lastIndexOf('\n', i1);
601                 if (i3 < 0) {
602                     i3 = 0;
603                 }
604                 int i4 = template.indexOf('\n', i1);
605                 if (i4 < 0) {
606                     i4 = template.length();
607                 }
608
609                 if (i < i3) {
610                     ss.append(template.substring(i, i3));
611                 }
612                 i = i4;
613             } else {
614                 ss.append(template.substring(i, i1)).append(value1);
615                 i = i2 + 1;
616             }
617         }
618
619         String req = format == Format.XML ? XmlJsonUtil.removeEmptyStructXml(ss.toString())
620             : XmlJsonUtil.removeEmptyStructJson(originalTemplate, ss.toString());
621
622         if (format == Format.JSON) {
623             req = XmlJsonUtil.removeLastCommaJson(req);
624         }
625
626         long t2 = System.currentTimeMillis();
627         log.info("Building {} completed. Time: {}", format, t2 - t1);
628
629         return req;
630     }
631
632     protected String expandRepeats(SvcLogicContext ctx, String template, int level) throws SvcLogicException {
633         StringBuilder newTemplate = new StringBuilder();
634         int k = 0;
635         while (k < template.length()) {
636             int i1 = template.indexOf("${repeat:", k);
637             if (i1 < 0) {
638                 newTemplate.append(template.substring(k));
639                 break;
640             }
641
642             int i2 = template.indexOf(':', i1 + 9);
643             if (i2 < 0) {
644                 throw new SvcLogicException(
645                     "Template error: Context variable name followed by : is required after repeat");
646             }
647
648             // Find the closing }, store in i3
649             int nn = 1;
650             int i3 = -1;
651             int i = i2;
652             while (nn > 0 && i < template.length()) {
653                 i3 = template.indexOf('}', i);
654                 if (i3 < 0) {
655                     throw new SvcLogicException("Template error: Matching } not found");
656                 }
657                 int i32 = template.indexOf('{', i);
658                 if (i32 >= 0 && i32 < i3) {
659                     nn++;
660                     i = i32 + 1;
661                 } else {
662                     nn--;
663                     i = i3 + 1;
664                 }
665             }
666
667             String var1 = template.substring(i1 + 9, i2);
668             String value1 = ctx.getAttribute(var1);
669             log.info("     {}:{}", var1, value1);
670             int n = 0;
671             try {
672                 n = Integer.parseInt(value1);
673             } catch (NumberFormatException e) {
674                 log.info("value1 not set or not a number, n will remain set at zero");
675             }
676
677             newTemplate.append(template.substring(k, i1));
678
679             String rpt = template.substring(i2 + 1, i3);
680
681             for (int ii = 0; ii < n; ii++) {
682                 String ss = rpt.replaceAll("\\[\\$\\{" + level + "\\}\\]", "[" + ii + "]");
683                 if (ii == n - 1 && ss.trim().endsWith(",")) {
684                     int i4 = ss.lastIndexOf(',');
685                     if (i4 > 0) {
686                         ss = ss.substring(0, i4) + ss.substring(i4 + 1);
687                     }
688                 }
689                 newTemplate.append(ss);
690             }
691
692             k = i3 + 1;
693         }
694
695         if (k == 0) {
696             return newTemplate.toString();
697         }
698
699         return expandRepeats(ctx, newTemplate.toString(), level + 1);
700     }
701
702     protected String readFile(String fileName) throws SvcLogicException {
703         try {
704             byte[] encoded = Files.readAllBytes(Paths.get(fileName));
705             return new String(encoded, "UTF-8");
706         } catch (IOException | SecurityException e) {
707             throw new SvcLogicException("Unable to read file " + fileName + e.getLocalizedMessage(), e);
708         }
709     }
710
711     protected Client addAuthType(Client c, FileParam fp) throws SvcLogicException {
712         Parameters p = new Parameters();
713         p.restapiUser = fp.user;
714         p.restapiPassword = fp.password;
715         p.oAuthConsumerKey = fp.oAuthConsumerKey;
716         p.oAuthVersion = fp.oAuthVersion;
717         p.oAuthConsumerSecret = fp.oAuthConsumerSecret;
718         p.oAuthSignatureMethod = fp.oAuthSignatureMethod;
719         p.authtype = fp.authtype;
720         return addAuthType(c, p);
721     }
722
723     public Client addAuthType(Client client, Parameters p) throws SvcLogicException {
724         if (p.authtype == AuthType.Unspecified) {
725             if (p.restapiUser != null && p.restapiPassword != null) {
726                 client.register(HttpAuthenticationFeature.basic(p.restapiUser, p.restapiPassword));
727             } else if (p.oAuthConsumerKey != null && p.oAuthConsumerSecret != null && p.oAuthSignatureMethod != null) {
728                 Feature oAuth1Feature =
729                     OAuth1ClientSupport.builder(new ConsumerCredentials(p.oAuthConsumerKey, p.oAuthConsumerSecret))
730                         .version(p.oAuthVersion).signatureMethod(p.oAuthSignatureMethod).feature().build();
731                 client.register(oAuth1Feature);
732
733             }
734         } else {
735             if (p.authtype == AuthType.DIGEST) {
736                 if (p.restapiUser != null && p.restapiPassword != null) {
737                     client.register(HttpAuthenticationFeature.digest(p.restapiUser, p.restapiPassword));
738                 } else {
739                     throw new SvcLogicException(
740                         "oAUTH authentication type selected but all restapiUser and restapiPassword "
741                             + "parameters doesn't exist",
742                         new Throwable());
743                 }
744             } else if (p.authtype == AuthType.BASIC) {
745                 if (p.restapiUser != null && p.restapiPassword != null) {
746                     client.register(HttpAuthenticationFeature.basic(p.restapiUser, p.restapiPassword));
747                 } else {
748                     throw new SvcLogicException(
749                         "oAUTH authentication type selected but all restapiUser and restapiPassword "
750                             + "parameters doesn't exist",
751                         new Throwable());
752                 }
753             } else if (p.authtype == AuthType.OAUTH) {
754                 if (p.oAuthConsumerKey != null && p.oAuthConsumerSecret != null && p.oAuthSignatureMethod != null) {
755                     Feature oAuth1Feature = OAuth1ClientSupport
756                         .builder(new ConsumerCredentials(p.oAuthConsumerKey, p.oAuthConsumerSecret))
757                         .version(p.oAuthVersion).signatureMethod(p.oAuthSignatureMethod).feature().build();
758                     client.register(oAuth1Feature);
759                 } else {
760                     throw new SvcLogicException(
761                         "oAUTH authentication type selected but all oAuthConsumerKey, oAuthConsumerSecret "
762                             + "and oAuthSignatureMethod parameters doesn't exist",
763                         new Throwable());
764                 }
765             }
766         }
767         return client;
768     }
769
770     /**
771      * Receives the http response for the http request sent.
772      *
773      * @param request request msg
774      * @param p parameters
775      * @return HTTP response
776      * @throws SvcLogicException when sending http request fails
777      */
778     public HttpResponse sendHttpRequest(String request, Parameters p) throws SvcLogicException {
779
780         SSLContext ssl = null;
781         if (p.ssl && p.restapiUrl.startsWith("https")) {
782             ssl = createSSLContext(p);
783         }
784         Client client;
785
786         if (ssl != null) {
787             HttpsURLConnection.setDefaultSSLSocketFactory(ssl.getSocketFactory());
788             client = ClientBuilder.newBuilder().sslContext(ssl).hostnameVerifier((s, sslSession) -> true).build();
789         } else {
790             client = ClientBuilder.newBuilder().hostnameVerifier((s, sslSession) -> true).build();
791         }
792         setClientTimeouts(client);
793         // Needed to support additional HTTP methods such as PATCH
794         client.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
795         client.register(new MetricLogClientFilter());
796         WebTarget webTarget = addAuthType(client, p).target(p.restapiUrl);
797
798         long t1 = System.currentTimeMillis();
799
800         HttpResponse r = new HttpResponse();
801         r.code = 200;
802         String accept = p.accept;
803         if (accept == null) {
804             accept = p.format == Format.XML ? "application/xml" : "application/json";
805         }
806
807         String contentType = p.contentType;
808         if (contentType == null) {
809             contentType = accept + ";charset=UTF-8";
810         }
811
812         if (!p.skipSending && !p.multipartFormData) {
813
814             Invocation.Builder invocationBuilder = webTarget.request(contentType).accept(accept);
815
816             if (p.format == Format.NONE) {
817                 invocationBuilder.header("", "");
818             }
819
820             if (p.customHttpHeaders != null && p.customHttpHeaders.length() > 0) {
821                 String[] keyValuePairs = p.customHttpHeaders.split(",");
822                 for (String singlePair : keyValuePairs) {
823                     int equalPosition = singlePair.indexOf('=');
824                     invocationBuilder.header(singlePair.substring(0, equalPosition),
825                         singlePair.substring(equalPosition + 1, singlePair.length()));
826                 }
827             }
828
829             invocationBuilder.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
830
831             Response response;
832
833             try {
834                 // When the HTTP operation has no body do not set the content-type
835                 //setting content-type has caused errors with some servers when no body is present
836                 if (request == null) {
837                     response = invocationBuilder.method(p.httpMethod.toString());
838                 } else {
839                     log.info("Sending request below to url " + p.restapiUrl);
840                     log.info(request);
841                     response = invocationBuilder.method(p.httpMethod.toString(), entity(request, contentType));
842                 }
843             } catch (ProcessingException | IllegalStateException e) {
844                 throw new SvcLogicException(requestPostingException + e.getLocalizedMessage(), e);
845             }
846
847             r.code = response.getStatus();
848             r.headers = response.getStringHeaders();
849             EntityTag etag = response.getEntityTag();
850             if (etag != null) {
851                 r.message = etag.getValue();
852             }
853             if (response.hasEntity() && r.code != 204) {
854                 r.body = response.readEntity(String.class);
855             }
856         } else if (!p.skipSending && p.multipartFormData) {
857
858             WebTarget wt = client.register(MultiPartFeature.class).target(p.restapiUrl);
859
860             MultiPart multiPart = new MultiPart();
861             multiPart.setMediaType(MediaType.MULTIPART_FORM_DATA_TYPE);
862
863             FileDataBodyPart fileDataBodyPart =
864                 new FileDataBodyPart("file", new File(p.multipartFile), MediaType.APPLICATION_OCTET_STREAM_TYPE);
865             multiPart.bodyPart(fileDataBodyPart);
866
867
868             Invocation.Builder invocationBuilder = wt.request(contentType).accept(accept);
869
870             if (p.format == Format.NONE) {
871                 invocationBuilder.header("", "");
872             }
873
874             if (p.customHttpHeaders != null && p.customHttpHeaders.length() > 0) {
875                 String[] keyValuePairs = p.customHttpHeaders.split(",");
876                 for (String singlePair : keyValuePairs) {
877                     int equalPosition = singlePair.indexOf('=');
878                     invocationBuilder.header(singlePair.substring(0, equalPosition),
879                         singlePair.substring(equalPosition + 1, singlePair.length()));
880                 }
881             }
882
883             Response response;
884
885             try {
886                 response =
887                     invocationBuilder.method(p.httpMethod.toString(), entity(multiPart, multiPart.getMediaType()));
888             } catch (ProcessingException | IllegalStateException e) {
889                 throw new SvcLogicException(requestPostingException + e.getLocalizedMessage(), e);
890             }
891
892             r.code = response.getStatus();
893             r.headers = response.getStringHeaders();
894             EntityTag etag = response.getEntityTag();
895             if (etag != null) {
896                 r.message = etag.getValue();
897             }
898             if (response.hasEntity() && r.code != 204) {
899                 r.body = response.readEntity(String.class);
900             }
901
902         }
903
904         long t2 = System.currentTimeMillis();
905         log.info(responseReceivedMessage, t2 - t1);
906         log.info(responseHttpCodeMessage, r.code);
907         log.info("HTTP response message: {}", r.message);
908         logHeaders(r.headers);
909         log.info("HTTP response: {}", r.body);
910
911         return r;
912     }
913
914     protected SSLContext createSSLContext(Parameters p) {
915         try (FileInputStream in = new FileInputStream(p.keyStoreFileName)) {
916             System.setProperty("jsse.enableSNIExtension", "false");
917             System.setProperty("javax.net.ssl.trustStore", p.trustStoreFileName);
918             System.setProperty("javax.net.ssl.trustStorePassword", p.trustStorePassword);
919
920             HttpsURLConnection.setDefaultHostnameVerifier((string, ssls) -> true);
921
922             KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
923             KeyStore ks = KeyStore.getInstance("PKCS12");
924             char[] pwd = p.keyStorePassword.toCharArray();
925             ks.load(in, pwd);
926             kmf.init(ks, pwd);
927
928             SSLContext ctx = SSLContext.getInstance("TLS");
929             ctx.init(kmf.getKeyManagers(), null, null);
930             return ctx;
931         } catch (Exception e) {
932             log.error("Error creating SSLContext: {}", e.getMessage(), e);
933         }
934         return null;
935     }
936
937     protected void setFailureResponseStatus(SvcLogicContext ctx, String prefix, String errorMessage,
938         HttpResponse resp) {
939         resp.code = 500;
940         resp.message = errorMessage;
941         String pp = prefix != null ? prefix + '.' : "";
942         ctx.setAttribute(pp + "response-code", String.valueOf(resp.code));
943         ctx.setAttribute(pp + "response-message", resp.message);
944     }
945
946     protected void setResponseStatus(SvcLogicContext ctx, String prefix, HttpResponse r) {
947         String pp = prefix != null ? prefix + '.' : "";
948         ctx.setAttribute(pp + "response-code", String.valueOf(r.code));
949         ctx.setAttribute(pp + "response-message", r.message);
950     }
951
952     public void sendFile(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException {
953         HttpResponse r = null;
954         try {
955             FileParam p = getFileParameters(paramMap);
956             byte[] data = Files.readAllBytes(Paths.get(p.fileName));
957
958             r = sendHttpData(data, p);
959             setResponseStatus(ctx, p.responsePrefix, r);
960
961         } catch (SvcLogicException | IOException e) {
962             log.error("Error sending the request: {}", e.getMessage(), e);
963
964             r = new HttpResponse();
965             r.code = 500;
966             r.message = e.getMessage();
967             String prefix = parseParam(paramMap, responsePrefix, false, null);
968             setResponseStatus(ctx, prefix, r);
969         }
970
971         if (r != null && r.code >= 300) {
972             throw new SvcLogicException(String.valueOf(r.code) + ": " + r.message);
973         }
974     }
975
976     private FileParam getFileParameters(Map<String, String> paramMap) throws SvcLogicException {
977         FileParam p = new FileParam();
978         p.fileName = parseParam(paramMap, "fileName", true, null);
979         p.url = parseParam(paramMap, "url", true, null);
980         p.user = parseParam(paramMap, "user", false, null);
981         p.password = parseParam(paramMap, "password", false, null);
982         p.httpMethod = HttpMethod.fromString(parseParam(paramMap, "httpMethod", false, "post"));
983         p.responsePrefix = parseParam(paramMap, responsePrefix, false, null);
984         String skipSendingStr = paramMap.get(skipSendingMessage);
985         p.skipSending = "true".equalsIgnoreCase(skipSendingStr);
986         p.oAuthConsumerKey = parseParam(paramMap, "oAuthConsumerKey", false, null);
987         p.oAuthVersion = parseParam(paramMap, "oAuthVersion", false, null);
988         p.oAuthConsumerSecret = parseParam(paramMap, "oAuthConsumerSecret", false, null);
989         p.oAuthSignatureMethod = parseParam(paramMap, "oAuthSignatureMethod", false, null);
990         p.authtype = fromString(parseParam(paramMap, "authType", false, "unspecified"));
991         return p;
992     }
993
994     public void postMessageOnUeb(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException {
995         HttpResponse r;
996         try {
997             UebParam p = getUebParameters(paramMap);
998
999             String pp = p.responsePrefix != null ? p.responsePrefix + '.' : "";
1000
1001             String req;
1002
1003             if (p.templateFileName == null) {
1004                 log.info("No template file name specified. Using default UEB template: {}", defaultUebTemplateFileName);
1005                 p.templateFileName = defaultUebTemplateFileName;
1006             }
1007
1008             String reqTemplate = readFile(p.templateFileName);
1009             reqTemplate = reqTemplate.replaceAll("rootVarName", p.rootVarName);
1010             req = buildXmlJsonRequest(ctx, reqTemplate, Format.JSON);
1011
1012             r = postOnUeb(req, p);
1013             setResponseStatus(ctx, p.responsePrefix, r);
1014             if (r.body != null) {
1015                 ctx.setAttribute(pp + "httpResponse", r.body);
1016             }
1017
1018         } catch (SvcLogicException e) {
1019             log.error("Error sending the request: {}", e.getMessage(), e);
1020
1021             r = new HttpResponse();
1022             r.code = 500;
1023             r.message = e.getMessage();
1024             String prefix = parseParam(paramMap, responsePrefix, false, null);
1025             setResponseStatus(ctx, prefix, r);
1026         }
1027
1028         if (r.code >= 300) {
1029             throw new SvcLogicException(String.valueOf(r.code) + ": " + r.message);
1030         }
1031     }
1032
1033     protected HttpResponse sendHttpData(byte[] data, FileParam p) throws SvcLogicException {
1034
1035         Client client = ClientBuilder.newBuilder().build();
1036         setClientTimeouts(client);
1037         client.property(ClientProperties.FOLLOW_REDIRECTS, true);
1038         WebTarget webTarget = addAuthType(client, p).target(p.url);
1039
1040         log.info("Sending file");
1041         long t1 = System.currentTimeMillis();
1042
1043         HttpResponse r = new HttpResponse();
1044         r.code = 200;
1045
1046         if (!p.skipSending) {
1047             String tt = "application/octet-stream";
1048             Invocation.Builder invocationBuilder = webTarget.request(tt).accept(tt);
1049
1050             Response response;
1051
1052             try {
1053                 if (p.httpMethod == HttpMethod.POST) {
1054                     response = invocationBuilder.post(Entity.entity(data, tt));
1055                 } else if (p.httpMethod == HttpMethod.PUT) {
1056                     response = invocationBuilder.put(Entity.entity(data, tt));
1057                 } else {
1058                     throw new SvcLogicException("Http operation" + p.httpMethod + "not supported");
1059                 }
1060             } catch (ProcessingException e) {
1061                 throw new SvcLogicException(requestPostingException + e.getLocalizedMessage(), e);
1062             }
1063
1064             r.code = response.getStatus();
1065             r.headers = response.getStringHeaders();
1066             EntityTag etag = response.getEntityTag();
1067             if (etag != null) {
1068                 r.message = etag.getValue();
1069             }
1070             if (response.hasEntity() && r.code != 204) {
1071                 r.body = response.readEntity(String.class);
1072             }
1073
1074             if (r.code == 301) {
1075                 String newUrl = response.getStringHeaders().getFirst("Location");
1076
1077                 log.info("Got response code 301. Sending same request to URL: {}", newUrl);
1078
1079                 webTarget = client.target(newUrl);
1080                 invocationBuilder = webTarget.request(tt).accept(tt);
1081
1082                 try {
1083                     if (p.httpMethod == HttpMethod.POST) {
1084                         response = invocationBuilder.post(Entity.entity(data, tt));
1085                     } else if (p.httpMethod == HttpMethod.PUT) {
1086                         response = invocationBuilder.put(Entity.entity(data, tt));
1087                     } else {
1088                         throw new SvcLogicException("Http operation" + p.httpMethod + "not supported");
1089                     }
1090                 } catch (ProcessingException e) {
1091                     throw new SvcLogicException(requestPostingException + e.getLocalizedMessage(), e);
1092                 }
1093
1094                 r.code = response.getStatus();
1095                 etag = response.getEntityTag();
1096                 if (etag != null) {
1097                     r.message = etag.getValue();
1098                 }
1099                 if (response.hasEntity() && r.code != 204) {
1100                     r.body = response.readEntity(String.class);
1101                 }
1102             }
1103         }
1104
1105         long t2 = System.currentTimeMillis();
1106         log.info(responseReceivedMessage, t2 - t1);
1107         log.info(responseHttpCodeMessage, r.code);
1108         log.info("HTTP response message: {}", r.message);
1109         logHeaders(r.headers);
1110         log.info("HTTP response: {}", r.body);
1111
1112         return r;
1113     }
1114
1115     private UebParam getUebParameters(Map<String, String> paramMap) throws SvcLogicException {
1116         UebParam p = new UebParam();
1117         p.topic = parseParam(paramMap, "topic", true, null);
1118         p.templateFileName = parseParam(paramMap, "templateFileName", false, null);
1119         p.rootVarName = parseParam(paramMap, "rootVarName", false, null);
1120         p.responsePrefix = parseParam(paramMap, responsePrefix, false, null);
1121         String skipSendingStr = paramMap.get(skipSendingMessage);
1122         p.skipSending = "true".equalsIgnoreCase(skipSendingStr);
1123         return p;
1124     }
1125
1126     protected void logProperties(Map<String, Object> mm) {
1127         List<String> ll = new ArrayList<>();
1128         for (Object o : mm.keySet()) {
1129             ll.add((String) o);
1130         }
1131         Collections.sort(ll);
1132
1133         log.info("Properties:");
1134         for (String name : ll) {
1135             log.info("--- {}:{}", name, String.valueOf(mm.get(name)));
1136         }
1137     }
1138
1139     protected void logHeaders(MultivaluedMap<String, String> mm) {
1140         log.info("HTTP response headers:");
1141
1142         if (mm == null) {
1143             return;
1144         }
1145
1146         List<String> ll = new ArrayList<>();
1147         for (Object o : mm.keySet()) {
1148             ll.add((String) o);
1149         }
1150         Collections.sort(ll);
1151
1152         for (String name : ll) {
1153             log.info("--- {}:{}", name, String.valueOf(mm.get(name)));
1154         }
1155     }
1156
1157     protected HttpResponse postOnUeb(String request, UebParam p) throws SvcLogicException {
1158         String[] urls = uebServers.split(" ");
1159         for (int i = 0; i < urls.length; i++) {
1160             if (!urls[i].endsWith("/")) {
1161                 urls[i] += "/";
1162             }
1163             urls[i] += "events/" + p.topic;
1164         }
1165
1166         Client client = ClientBuilder.newBuilder().build();
1167         setClientTimeouts(client);
1168         WebTarget webTarget = client.target(urls[0]);
1169
1170         log.info("UEB URL: {}", urls[0]);
1171         log.info("Sending request:");
1172         log.info(request);
1173         long t1 = System.currentTimeMillis();
1174
1175         HttpResponse r = new HttpResponse();
1176         r.code = 200;
1177
1178         if (!p.skipSending) {
1179             String tt = "application/json";
1180             String tt1 = tt + ";charset=UTF-8";
1181
1182             Response response;
1183             Invocation.Builder invocationBuilder = webTarget.request(tt1).accept(tt);
1184
1185             try {
1186                 response = invocationBuilder.post(Entity.entity(request, tt1));
1187             } catch (ProcessingException e) {
1188                 throw new SvcLogicException(requestPostingException + e.getLocalizedMessage(), e);
1189             }
1190             r.code = response.getStatus();
1191             r.headers = response.getStringHeaders();
1192             if (response.hasEntity()) {
1193                 r.body = response.readEntity(String.class);
1194             }
1195         }
1196
1197         long t2 = System.currentTimeMillis();
1198         log.info(responseReceivedMessage, t2 - t1);
1199         log.info(responseHttpCodeMessage, r.code);
1200         logHeaders(r.headers);
1201         log.info("HTTP response:\n {}", r.body);
1202
1203         return r;
1204     }
1205
1206     public void setUebServers(String uebServers) {
1207         this.uebServers = uebServers;
1208     }
1209
1210     public void setDefaultUebTemplateFileName(String defaultUebTemplateFileName) {
1211         this.defaultUebTemplateFileName = defaultUebTemplateFileName;
1212     }
1213
1214     protected void setClientTimeouts(Client client) {
1215         client.property(ClientProperties.CONNECT_TIMEOUT, httpConnectTimeout);
1216         client.property(ClientProperties.READ_TIMEOUT, httpReadTimeout);
1217     }
1218
1219     protected Integer readOptionalInteger(String propertyName, Integer defaultValue) {
1220         String stringValue = System.getProperty(propertyName);
1221         if (stringValue != null && stringValue.length() > 0) {
1222             try {
1223                 return Integer.valueOf(stringValue);
1224             } catch (NumberFormatException e) {
1225                 log.warn("property " + propertyName + " had the value " + stringValue + " that could not be converted to an Integer, default " + defaultValue + " will be used instead", e);
1226             }
1227         }
1228         return defaultValue;
1229     }
1230
1231
1232     private static class FileParam {
1233
1234         public String fileName;
1235         public String url;
1236         public String user;
1237         public String password;
1238         public HttpMethod httpMethod;
1239         public String responsePrefix;
1240         public boolean skipSending;
1241         public String oAuthConsumerKey;
1242         public String oAuthConsumerSecret;
1243         public String oAuthSignatureMethod;
1244         public String oAuthVersion;
1245         public AuthType authtype;
1246     }
1247
1248     private static class UebParam {
1249
1250         public String topic;
1251         public String templateFileName;
1252         public String rootVarName;
1253         public String responsePrefix;
1254         public boolean skipSending;
1255     }
1256 }