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