2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property.
6 * Copyright © 2017 Amdocs
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
24 package org.openecomp.modelloader.restclient;
26 import com.sun.jersey.api.client.Client;
27 import com.sun.jersey.api.client.ClientResponse;
28 import com.sun.jersey.api.client.config.ClientConfig;
29 import com.sun.jersey.api.client.config.DefaultClientConfig;
30 import com.sun.jersey.api.client.filter.LoggingFilter;
31 import com.sun.jersey.client.urlconnection.HTTPSProperties;
32 import org.openecomp.cl.api.LogFields;
33 import org.openecomp.cl.api.LogLine;
34 import org.openecomp.cl.api.Logger;
35 import org.openecomp.cl.eelf.LoggerFactory;
36 import org.openecomp.cl.mdc.MdcContext;
37 import org.openecomp.cl.mdc.MdcOverride;
38 import org.openecomp.modelloader.config.ModelLoaderConfig;
39 import org.openecomp.modelloader.service.ModelLoaderMsgs;
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Node;
42 import org.w3c.dom.NodeList;
43 import org.xml.sax.InputSource;
44 import org.xml.sax.SAXException;
46 import java.io.ByteArrayOutputStream;
47 import java.io.FileInputStream;
48 import java.io.IOException;
49 import java.io.PrintStream;
50 import java.io.StringReader;
51 import java.security.GeneralSecurityException;
52 import java.security.KeyStore;
53 import java.security.cert.X509Certificate;
54 import java.text.SimpleDateFormat;
56 import javax.net.ssl.HostnameVerifier;
57 import javax.net.ssl.HttpsURLConnection;
58 import javax.net.ssl.KeyManagerFactory;
59 import javax.net.ssl.SSLContext;
60 import javax.net.ssl.SSLSession;
61 import javax.net.ssl.TrustManager;
62 import javax.net.ssl.X509TrustManager;
63 import javax.ws.rs.core.Response;
64 import javax.xml.parsers.DocumentBuilder;
65 import javax.xml.parsers.DocumentBuilderFactory;
66 import javax.xml.parsers.ParserConfigurationException;
68 public class AaiRestClient {
69 public enum MimeType {
70 XML("application/xml"), JSON("application/json");
72 private String httpType;
74 MimeType(String httpType) {
75 this.httpType = httpType;
78 String getHttpHeaderType() {
83 private static String HEADER_TRANS_ID = "X-TransactionId";
84 private static String HEADER_FROM_APP_ID = "X-FromAppId";
85 private static String HEADER_AUTHORIZATION = "Authorization";
86 private static String ML_APP_NAME = "ModelLoader";
87 private static String RESOURCE_VERSION_PARAM = "resource-version";
89 private static SimpleDateFormat dateFormatter = new SimpleDateFormat(
90 "yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
92 private static Logger logger = LoggerFactory.getInstance()
93 .getLogger(AaiRestClient.class.getName());
94 private static Logger metricsLogger = LoggerFactory.getInstance()
95 .getMetricsLogger(AaiRestClient.class.getName());
97 private ModelLoaderConfig config = null;
99 public AaiRestClient(ModelLoaderConfig config) {
100 this.config = config;
104 * Send a PUT request to the A&AI.
111 * - the XML or JSON payload for the request
113 * - the content type (XML or JSON)
114 * @return ClientResponse
116 public ClientResponse putResource(String url, String payload, String transId, MimeType mimeType) {
117 ClientResponse result = null;
118 ByteArrayOutputStream baos = new ByteArrayOutputStream();
119 long startTimeInMs = 0;
120 MdcOverride override = new MdcOverride();
123 Client client = setupClient();
125 baos = new ByteArrayOutputStream();
126 PrintStream ps = new PrintStream(baos);
127 if (logger.isDebugEnabled()) {
128 client.addFilter(new LoggingFilter(ps));
131 // Grab the current time so that we can use it for metrics purposes later.
132 startTimeInMs = System.currentTimeMillis();
133 override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs));
135 if (useBasicAuth()) {
136 result = client.resource(url).header(HEADER_TRANS_ID, transId)
137 .header(HEADER_FROM_APP_ID, ML_APP_NAME)
138 .header(HEADER_AUTHORIZATION, getAuthenticationCredentials())
139 .type(mimeType.getHttpHeaderType()).put(ClientResponse.class, payload);
141 result = client.resource(url).header(HEADER_TRANS_ID, transId)
142 .header(HEADER_FROM_APP_ID, ML_APP_NAME).type(mimeType.getHttpHeaderType())
143 .put(ClientResponse.class, payload);
145 } catch (Exception ex) {
146 logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "PUT", url, ex.getLocalizedMessage());
149 if (logger.isDebugEnabled()) {
150 logger.debug(baos.toString());
154 if ((result != null) && ((result.getStatus() == Response.Status.CREATED.getStatusCode())
155 || (result.getStatus() == Response.Status.OK.getStatusCode()))) {
156 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "PUT", url,
157 Integer.toString(result.getStatus()));
158 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS,
159 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus())
160 .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION,
161 result.getResponseStatus().toString()),
162 override, "PUT", url, Integer.toString(result.getStatus()));
164 // If response is not 200 OK, then additionally log the reason
165 String respMsg = result.getEntity(String.class);
166 if (respMsg == null) {
167 respMsg = result.getStatusInfo().getReasonPhrase();
169 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL, "PUT", url,
170 Integer.toString(result.getStatus()), respMsg);
171 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL,
172 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus())
173 .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION,
174 result.getResponseStatus().toString()),
175 override, "PUT", url, Integer.toString(result.getStatus()), respMsg);
182 * Send a DELETE request to the A&AI.
186 * @param resourceVersion
187 * - the resource-version of the model to delete
190 * @return ClientResponse
192 public ClientResponse deleteResource(String url, String resourceVersion, String transId) {
193 ClientResponse result = null;
194 ByteArrayOutputStream baos = new ByteArrayOutputStream();
195 long startTimeInMs = 0;
196 MdcOverride override = new MdcOverride();
199 Client client = setupClient();
201 baos = new ByteArrayOutputStream();
202 PrintStream ps = new PrintStream(baos);
203 if (logger.isDebugEnabled()) {
204 client.addFilter(new LoggingFilter(ps));
207 // Grab the current time so that we can use it for metrics purposes later.
208 startTimeInMs = System.currentTimeMillis();
209 override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs));
211 if (useBasicAuth()) {
212 result = client.resource(url).queryParam(RESOURCE_VERSION_PARAM, resourceVersion)
213 .header(HEADER_TRANS_ID, transId).header(HEADER_FROM_APP_ID, ML_APP_NAME)
214 .header(HEADER_AUTHORIZATION, getAuthenticationCredentials())
215 .delete(ClientResponse.class);
217 result = client.resource(url).queryParam(RESOURCE_VERSION_PARAM, resourceVersion)
218 .header(HEADER_TRANS_ID, transId).header(HEADER_FROM_APP_ID, ML_APP_NAME)
219 .delete(ClientResponse.class);
221 } catch (Exception ex) {
222 logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "DELETE", url, ex.getLocalizedMessage());
225 if (logger.isDebugEnabled()) {
226 logger.debug(baos.toString());
230 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "DELETE", url,
231 Integer.toString(result.getStatus()));
232 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS,
233 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus()).setField(
234 LogLine.DefinedFields.RESPONSE_DESCRIPTION, result.getResponseStatus().toString()),
235 override, "DELETE", url, Integer.toString(result.getStatus()));
241 * Send a GET request to the A&AI for a resource.
247 * @return ClientResponse
249 public ClientResponse getResource(String url, String transId, MimeType mimeType) {
250 ClientResponse result = null;
251 ByteArrayOutputStream baos = new ByteArrayOutputStream();
252 long startTimeInMs = 0;
253 MdcOverride override = new MdcOverride();
256 Client client = setupClient();
258 baos = new ByteArrayOutputStream();
259 PrintStream ps = new PrintStream(baos);
260 if (logger.isDebugEnabled()) {
261 client.addFilter(new LoggingFilter(ps));
264 // Grab the current time so that we can use it for metrics purposes later.
265 startTimeInMs = System.currentTimeMillis();
266 override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs));
268 if (useBasicAuth()) {
269 result = client.resource(url).header(HEADER_TRANS_ID, transId)
270 .header(HEADER_FROM_APP_ID, ML_APP_NAME).accept(mimeType.getHttpHeaderType())
271 .header(HEADER_AUTHORIZATION, getAuthenticationCredentials()).get(ClientResponse.class);
273 result = client.resource(url).header(HEADER_TRANS_ID, transId)
274 .header(HEADER_FROM_APP_ID, ML_APP_NAME).accept(mimeType.getHttpHeaderType())
275 .get(ClientResponse.class);
278 } catch (Exception ex) {
279 logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "GET", url, ex.getLocalizedMessage());
282 if (logger.isDebugEnabled()) {
283 logger.debug(baos.toString());
287 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "GET", url,
288 Integer.toString(result.getStatus()));
289 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS,
290 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus()).setField(
291 LogLine.DefinedFields.RESPONSE_DESCRIPTION, result.getResponseStatus().toString()),
292 override, "GET", url, Integer.toString(result.getStatus()));
298 * Send a POST request to the A&AI.
305 * - the XML or JSON payload for the request
307 * - the content type (XML or JSON)
308 * @return ClientResponse
310 public ClientResponse postResource(String url, String payload, String transId, MimeType mimeType) {
311 ClientResponse result = null;
312 ByteArrayOutputStream baos = new ByteArrayOutputStream();
313 long startTimeInMs = 0;
314 MdcOverride override = new MdcOverride();
317 Client client = setupClient();
319 baos = new ByteArrayOutputStream();
320 PrintStream ps = new PrintStream(baos);
321 if (logger.isDebugEnabled()) {
322 client.addFilter(new LoggingFilter(ps));
325 // Grab the current time so that we can use it for metrics purposes later.
326 startTimeInMs = System.currentTimeMillis();
327 override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs));
329 if (useBasicAuth()) {
330 result = client.resource(url).header(HEADER_TRANS_ID, transId)
331 .header(HEADER_FROM_APP_ID, ML_APP_NAME)
332 .header(HEADER_AUTHORIZATION, getAuthenticationCredentials())
333 .type(mimeType.getHttpHeaderType()).post(ClientResponse.class, payload);
335 result = client.resource(url).header(HEADER_TRANS_ID, transId)
336 .header(HEADER_FROM_APP_ID, ML_APP_NAME).type(mimeType.getHttpHeaderType())
337 .post(ClientResponse.class, payload);
339 } catch (Exception ex) {
340 logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "POST", url, ex.getLocalizedMessage());
343 if (logger.isDebugEnabled()) {
344 logger.debug(baos.toString());
348 if ((result != null) && ((result.getStatus() == Response.Status.CREATED.getStatusCode())
349 || (result.getStatus() == Response.Status.OK.getStatusCode()))) {
350 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "POST", url,
351 Integer.toString(result.getStatus()));
352 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS,
353 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus())
354 .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION,
355 result.getResponseStatus().toString()),
356 override, "POST", url, Integer.toString(result.getStatus()));
358 // If response is not 200 OK, then additionally log the reason
359 String respMsg = result.getEntity(String.class);
360 if (respMsg == null) {
361 respMsg = result.getStatusInfo().getReasonPhrase();
363 logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL, "POST", url,
364 Integer.toString(result.getStatus()), respMsg);
365 metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL,
366 new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus())
367 .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION,
368 result.getResponseStatus().toString()),
369 override, "POST", url, Integer.toString(result.getStatus()), respMsg);
376 * Does a GET on a resource to retrieve the resource version, and then DELETE
383 * @return ClientResponse
385 public ClientResponse getAndDeleteResource(String url, String transId) {
386 // First, GET the model
387 ClientResponse getResponse = getResource(url, transId, MimeType.XML);
388 if ((getResponse == null) || (getResponse.getStatus() != Response.Status.OK.getStatusCode())) {
392 // Delete the model using the resource version in the response
393 String resVersion = null;
395 resVersion = getResourceVersion(getResponse);
396 } catch (Exception e) {
397 logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "GET", url, e.getLocalizedMessage());
401 return deleteResource(url, resVersion, transId);
404 private Client setupClient() throws IOException, GeneralSecurityException {
405 ClientConfig clientConfig = new DefaultClientConfig();
407 HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
409 public boolean verify(String string, SSLSession ssls) {
414 // Create a trust manager that does not validate certificate chains
415 TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
417 public X509Certificate[] getAcceptedIssuers() {
422 public void checkClientTrusted(X509Certificate[] certs, String authType) {}
425 public void checkServerTrusted(X509Certificate[] certs, String authType) {}
428 SSLContext ctx = SSLContext.getInstance("TLS");
429 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
430 FileInputStream fin = new FileInputStream(config.getAaiKeyStorePath());
431 KeyStore ks = KeyStore.getInstance("PKCS12");
432 char[] pwd = config.getAaiKeyStorePassword().toCharArray();
436 ctx.init(kmf.getKeyManagers(), trustAllCerts, null);
437 clientConfig.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
438 new HTTPSProperties(new HostnameVerifier() {
440 public boolean verify(String theString, SSLSession sslSession) {
445 Client client = Client.create(clientConfig);
450 private String getResourceVersion(ClientResponse response)
451 throws ParserConfigurationException, SAXException, IOException {
452 String respData = response.getEntity(String.class);
454 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
455 DocumentBuilder builder = factory.newDocumentBuilder();
456 InputSource is = new InputSource(new StringReader(respData));
457 Document doc = builder.parse(is);
459 NodeList nodeList = doc.getDocumentElement().getChildNodes();
460 for (int i = 0; i < nodeList.getLength(); i++) {
461 Node currentNode = nodeList.item(i);
462 if (currentNode.getNodeName().equals(RESOURCE_VERSION_PARAM)) {
463 return currentNode.getTextContent();
470 private String getAuthenticationCredentials() {
472 String usernameAndPassword = config.getAaiAuthenticationUser() + ":"
473 + config.getAaiAuthenticationPassword();
474 return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());
477 public boolean useBasicAuth() {
478 return (config.getAaiAuthenticationUser() != null)
479 && (config.getAaiAuthenticationPassword() != null);