2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 Amdocs
7 * ===================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END============================================
21 package org.onap.aai.modelloader.restclient;
23 import com.sun.jersey.api.client.Client;
24 import com.sun.jersey.api.client.ClientResponse;
25 import com.sun.jersey.api.client.config.ClientConfig;
26 import com.sun.jersey.api.client.config.DefaultClientConfig;
27 import com.sun.jersey.api.client.filter.LoggingFilter;
28 import com.sun.jersey.client.urlconnection.HTTPSProperties;
30 import org.onap.aai.modelloader.config.ModelLoaderConfig;
31 import org.onap.aai.modelloader.restclient.AaiRestClient;
32 import org.onap.aai.modelloader.service.ModelLoaderMsgs;
33 import org.onap.aai.cl.api.LogFields;
34 import org.onap.aai.cl.api.LogLine;
35 import org.onap.aai.cl.api.Logger;
36 import org.onap.aai.cl.eelf.LoggerFactory;
37 import org.onap.aai.cl.mdc.MdcContext;
38 import org.onap.aai.cl.mdc.MdcOverride;
39 import org.w3c.dom.Document;
40 import org.w3c.dom.Node;
41 import org.w3c.dom.NodeList;
42 import org.xml.sax.InputSource;
43 import org.xml.sax.SAXException;
45 import java.io.ByteArrayOutputStream;
46 import java.io.FileInputStream;
47 import java.io.IOException;
48 import java.io.PrintStream;
49 import java.io.StringReader;
50 import java.security.GeneralSecurityException;
51 import java.security.KeyStore;
52 import java.security.cert.X509Certificate;
53 import java.text.SimpleDateFormat;
55 import javax.net.ssl.HostnameVerifier;
56 import javax.net.ssl.HttpsURLConnection;
57 import javax.net.ssl.KeyManagerFactory;
58 import javax.net.ssl.SSLContext;
59 import javax.net.ssl.SSLSession;
60 import javax.net.ssl.TrustManager;
61 import javax.net.ssl.X509TrustManager;
62 import javax.ws.rs.core.Response;
63 import javax.xml.parsers.DocumentBuilder;
64 import javax.xml.parsers.DocumentBuilderFactory;
65 import javax.xml.parsers.ParserConfigurationException;
67 public class AaiRestClient {
68 public enum MimeType {
69 XML("application/xml"), JSON("application/json");
71 private String httpType;
73 MimeType(String httpType) {
74 this.httpType = httpType;
77 String getHttpHeaderType() {
82 private static String HEADER_TRANS_ID = "X-TransactionId";
83 private static String HEADER_FROM_APP_ID = "X-FromAppId";
84 private static String HEADER_AUTHORIZATION = "Authorization";
85 private static String ML_APP_NAME = "ModelLoader";
86 private static String RESOURCE_VERSION_PARAM = "resource-version";
88 private static SimpleDateFormat dateFormatter = new SimpleDateFormat(
89 "yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
91 private static Logger logger = LoggerFactory.getInstance()
92 .getLogger(AaiRestClient.class.getName());
93 private static Logger metricsLogger = LoggerFactory.getInstance()
94 .getMetricsLogger(AaiRestClient.class.getName());
96 private ModelLoaderConfig config = null;
98 public AaiRestClient(ModelLoaderConfig config) {
103 * Send a PUT request to the A&AI.
110 * - the XML or JSON payload for the request
112 * - the content type (XML or JSON)
113 * @return ClientResponse
115 public ClientResponse putResource(String url, String payload, String transId, MimeType mimeType) {
116 ClientResponse result = null;
117 ByteArrayOutputStream baos = new ByteArrayOutputStream();
118 long startTimeInMs = 0;
119 MdcOverride override = new MdcOverride();
122 Client client = setupClient();
124 baos = new ByteArrayOutputStream();
125 PrintStream ps = new PrintStream(baos);
126 if (logger.isDebugEnabled()) {
127 client.addFilter(new LoggingFilter(ps));
130 // Grab the current time so that we can use it for metrics purposes later.
131 startTimeInMs = System.currentTimeMillis();
132 override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs));
134 if (useBasicAuth()) {
135 result = client.resource(url).header(HEADER_TRANS_ID, transId)
136 .header(HEADER_FROM_APP_ID, ML_APP_NAME)
137 .header(HEADER_AUTHORIZATION, getAuthenticationCredentials())
138 .type(mimeType.getHttpHeaderType()).put(ClientResponse.class, payload);
140 result = client.resource(url).header(HEADER_TRANS_ID, transId)
141 .header(HEADER_FROM_APP_ID, ML_APP_NAME).type(mimeType.getHttpHeaderType())
142 .put(ClientResponse.class, payload);
144 } catch (Exception ex) {
145 logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "PUT", url, ex.getLocalizedMessage());
148 if (logger.isDebugEnabled()) {
149 logger.debug(baos.toString());
153 if ((result != null) && ((result.getStatus() == Response.Status.CREATED.getStatusCode())
154 || (result.getStatus() == Response.Status.OK.getStatusCode()))) {
155 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "PUT", url,
156 Integer.toString(result.getStatus()));
157 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS,
158 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus())
159 .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION,
160 result.getResponseStatus().toString()),
161 override, "PUT", url, Integer.toString(result.getStatus()));
163 // If response is not 200 OK, then additionally log the reason
164 String respMsg = result.getEntity(String.class);
165 if (respMsg == null) {
166 respMsg = result.getStatusInfo().getReasonPhrase();
168 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL, "PUT", url,
169 Integer.toString(result.getStatus()), respMsg);
170 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL,
171 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus())
172 .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION,
173 result.getResponseStatus().toString()),
174 override, "PUT", url, Integer.toString(result.getStatus()), respMsg);
181 * Send a DELETE request to the A&AI.
185 * @param resourceVersion
186 * - the resource-version of the model to delete
189 * @return ClientResponse
191 public ClientResponse deleteResource(String url, String resourceVersion, String transId) {
192 ClientResponse result = null;
193 ByteArrayOutputStream baos = new ByteArrayOutputStream();
194 long startTimeInMs = 0;
195 MdcOverride override = new MdcOverride();
198 Client client = setupClient();
200 baos = new ByteArrayOutputStream();
201 PrintStream ps = new PrintStream(baos);
202 if (logger.isDebugEnabled()) {
203 client.addFilter(new LoggingFilter(ps));
206 // Grab the current time so that we can use it for metrics purposes later.
207 startTimeInMs = System.currentTimeMillis();
208 override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs));
210 if (useBasicAuth()) {
211 result = client.resource(url).queryParam(RESOURCE_VERSION_PARAM, resourceVersion)
212 .header(HEADER_TRANS_ID, transId).header(HEADER_FROM_APP_ID, ML_APP_NAME)
213 .header(HEADER_AUTHORIZATION, getAuthenticationCredentials())
214 .delete(ClientResponse.class);
216 result = client.resource(url).queryParam(RESOURCE_VERSION_PARAM, resourceVersion)
217 .header(HEADER_TRANS_ID, transId).header(HEADER_FROM_APP_ID, ML_APP_NAME)
218 .delete(ClientResponse.class);
220 } catch (Exception ex) {
221 logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "DELETE", url, ex.getLocalizedMessage());
224 if (logger.isDebugEnabled()) {
225 logger.debug(baos.toString());
229 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "DELETE", url,
230 Integer.toString(result.getStatus()));
231 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS,
232 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus()).setField(
233 LogLine.DefinedFields.RESPONSE_DESCRIPTION, result.getResponseStatus().toString()),
234 override, "DELETE", url, Integer.toString(result.getStatus()));
240 * Send a GET request to the A&AI for a resource.
246 * @return ClientResponse
248 public ClientResponse getResource(String url, String transId, MimeType mimeType) {
249 ClientResponse result = null;
250 ByteArrayOutputStream baos = new ByteArrayOutputStream();
251 long startTimeInMs = 0;
252 MdcOverride override = new MdcOverride();
255 Client client = setupClient();
257 baos = new ByteArrayOutputStream();
258 PrintStream ps = new PrintStream(baos);
259 if (logger.isDebugEnabled()) {
260 client.addFilter(new LoggingFilter(ps));
263 // Grab the current time so that we can use it for metrics purposes later.
264 startTimeInMs = System.currentTimeMillis();
265 override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs));
267 if (useBasicAuth()) {
268 result = client.resource(url).header(HEADER_TRANS_ID, transId)
269 .header(HEADER_FROM_APP_ID, ML_APP_NAME).accept(mimeType.getHttpHeaderType())
270 .header(HEADER_AUTHORIZATION, getAuthenticationCredentials()).get(ClientResponse.class);
272 result = client.resource(url).header(HEADER_TRANS_ID, transId)
273 .header(HEADER_FROM_APP_ID, ML_APP_NAME).accept(mimeType.getHttpHeaderType())
274 .get(ClientResponse.class);
277 } catch (Exception ex) {
278 logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "GET", url, ex.getLocalizedMessage());
281 if (logger.isDebugEnabled()) {
282 logger.debug(baos.toString());
286 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "GET", url,
287 Integer.toString(result.getStatus()));
288 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS,
289 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus()).setField(
290 LogLine.DefinedFields.RESPONSE_DESCRIPTION, result.getResponseStatus().toString()),
291 override, "GET", url, Integer.toString(result.getStatus()));
297 * Send a POST request to the A&AI.
304 * - the XML or JSON payload for the request
306 * - the content type (XML or JSON)
307 * @return ClientResponse
309 public ClientResponse postResource(String url, String payload, String transId, MimeType mimeType) {
310 ClientResponse result = null;
311 ByteArrayOutputStream baos = new ByteArrayOutputStream();
312 long startTimeInMs = 0;
313 MdcOverride override = new MdcOverride();
316 Client client = setupClient();
318 baos = new ByteArrayOutputStream();
319 PrintStream ps = new PrintStream(baos);
320 if (logger.isDebugEnabled()) {
321 client.addFilter(new LoggingFilter(ps));
324 // Grab the current time so that we can use it for metrics purposes later.
325 startTimeInMs = System.currentTimeMillis();
326 override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs));
328 if (useBasicAuth()) {
329 result = client.resource(url).header(HEADER_TRANS_ID, transId)
330 .header(HEADER_FROM_APP_ID, ML_APP_NAME)
331 .header(HEADER_AUTHORIZATION, getAuthenticationCredentials())
332 .type(mimeType.getHttpHeaderType()).post(ClientResponse.class, payload);
334 result = client.resource(url).header(HEADER_TRANS_ID, transId)
335 .header(HEADER_FROM_APP_ID, ML_APP_NAME).type(mimeType.getHttpHeaderType())
336 .post(ClientResponse.class, payload);
338 } catch (Exception ex) {
339 logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "POST", url, ex.getLocalizedMessage());
342 if (logger.isDebugEnabled()) {
343 logger.debug(baos.toString());
347 if ((result != null) && ((result.getStatus() == Response.Status.CREATED.getStatusCode())
348 || (result.getStatus() == Response.Status.OK.getStatusCode()))) {
349 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "POST", url,
350 Integer.toString(result.getStatus()));
351 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS,
352 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus())
353 .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION,
354 result.getResponseStatus().toString()),
355 override, "POST", url, Integer.toString(result.getStatus()));
357 // If response is not 200 OK, then additionally log the reason
358 String respMsg = result.getEntity(String.class);
359 if (respMsg == null) {
360 respMsg = result.getStatusInfo().getReasonPhrase();
362 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL, "POST", url,
363 Integer.toString(result.getStatus()), respMsg);
364 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL,
365 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus())
366 .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION,
367 result.getResponseStatus().toString()),
368 override, "POST", url, Integer.toString(result.getStatus()), respMsg);
375 * Does a GET on a resource to retrieve the resource version, and then DELETE
382 * @return ClientResponse
384 public ClientResponse getAndDeleteResource(String url, String transId) {
385 // First, GET the model
386 ClientResponse getResponse = getResource(url, transId, MimeType.XML);
387 if ((getResponse == null) || (getResponse.getStatus() != Response.Status.OK.getStatusCode())) {
391 // Delete the model using the resource version in the response
392 String resVersion = null;
394 resVersion = getResourceVersion(getResponse);
395 } catch (Exception e) {
396 logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "GET", url, e.getLocalizedMessage());
400 return deleteResource(url, resVersion, transId);
403 private Client setupClient() throws IOException, GeneralSecurityException {
404 ClientConfig clientConfig = new DefaultClientConfig();
406 HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
408 public boolean verify(String string, SSLSession ssls) {
413 // Create a trust manager that does not validate certificate chains
414 TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
416 public X509Certificate[] getAcceptedIssuers() {
421 public void checkClientTrusted(X509Certificate[] certs, String authType) {}
424 public void checkServerTrusted(X509Certificate[] certs, String authType) {}
427 SSLContext ctx = SSLContext.getInstance("TLS");
428 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
429 FileInputStream fin = new FileInputStream(config.getAaiKeyStorePath());
430 KeyStore ks = KeyStore.getInstance("PKCS12");
431 char[] pwd = config.getAaiKeyStorePassword().toCharArray();
435 ctx.init(kmf.getKeyManagers(), trustAllCerts, null);
436 clientConfig.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
437 new HTTPSProperties(new HostnameVerifier() {
439 public boolean verify(String theString, SSLSession sslSession) {
444 Client client = Client.create(clientConfig);
449 private String getResourceVersion(ClientResponse response)
450 throws ParserConfigurationException, SAXException, IOException {
451 String respData = response.getEntity(String.class);
453 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
454 DocumentBuilder builder = factory.newDocumentBuilder();
455 InputSource is = new InputSource(new StringReader(respData));
456 Document doc = builder.parse(is);
458 NodeList nodeList = doc.getDocumentElement().getChildNodes();
459 for (int i = 0; i < nodeList.getLength(); i++) {
460 Node currentNode = nodeList.item(i);
461 if (currentNode.getNodeName().equals(RESOURCE_VERSION_PARAM)) {
462 return currentNode.getTextContent();
469 private String getAuthenticationCredentials() {
471 String usernameAndPassword = config.getAaiAuthenticationUser() + ":"
472 + config.getAaiAuthenticationPassword();
473 return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());
476 public boolean useBasicAuth() {
477 return (config.getAaiAuthenticationUser() != null)
478 && (config.getAaiAuthenticationPassword() != null);