Convert project from AJSC to Spring Boot
[aai/model-loader.git] / src / main / java / org / onap / aai / modelloader / restclient / AaiRestClient.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017-2018 European Software Marketing Ltd.
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
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
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=========================================================
20  */
21 package org.onap.aai.modelloader.restclient;
22
23 import com.sun.jersey.core.util.MultivaluedMapImpl; // NOSONAR
24 import java.io.IOException;
25 import java.io.StringReader;
26 import java.net.URI;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.stream.IntStream;
31 import javax.ws.rs.core.MediaType;
32 import javax.ws.rs.core.MultivaluedMap;
33 import javax.ws.rs.core.Response;
34 import javax.ws.rs.core.UriBuilder;
35 import javax.xml.parsers.DocumentBuilder;
36 import javax.xml.parsers.DocumentBuilderFactory;
37 import javax.xml.parsers.ParserConfigurationException;
38 import org.onap.aai.cl.api.Logger;
39 import org.onap.aai.cl.eelf.LoggerFactory;
40 import org.onap.aai.modelloader.config.ModelLoaderConfig;
41 import org.onap.aai.modelloader.service.ModelLoaderMsgs;
42 import org.onap.aai.restclient.client.OperationResult;
43 import org.onap.aai.restclient.client.RestClient;
44 import org.onap.aai.restclient.enums.RestAuthenticationMode;
45 import org.w3c.dom.Document;
46 import org.w3c.dom.Node;
47 import org.w3c.dom.NodeList;
48 import org.xml.sax.InputSource;
49 import org.xml.sax.SAXException;
50
51 /**
52  * Wrapper around the standard A&AI Rest Client interface. This currently uses Jersey client 1.x
53  *
54  */
55 public class AaiRestClient {
56
57     public static final String HEADER_TRANS_ID = "X-TransactionId";
58     public static final String HEADER_FROM_APP_ID = "X-FromAppId";
59     public static final String ML_APP_NAME = "ModelLoader";
60     private static final String RESOURCE_VERSION_PARAM = "resource-version";
61
62     private static Logger logger = LoggerFactory.getInstance().getLogger(AaiRestClient.class.getName());
63
64     private ModelLoaderConfig config = null;
65
66     public AaiRestClient(ModelLoaderConfig config) {
67         this.config = config;
68     }
69
70
71     /**
72      * Send a GET request to the A&AI for a resource.
73      *
74      * @param url
75      * @param transId
76      * @param mediaType
77      * @return
78      */
79     public OperationResult getResource(String url, String transId, MediaType mediaType) {
80         return setupClient().get(url, buildHeaders(transId), mediaType);
81     }
82
83     /**
84      * Send a PUT request to the A&AI.
85      *
86      * @param url - the url
87      * @param payload - the XML or JSON payload for the request
88      * @param transId - transaction ID
89      * @param mediaType - the content type (XML or JSON)
90      * @return operation result
91      */
92     public OperationResult putResource(String url, String payload, String transId, MediaType mediaType) {
93         logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_PAYLOAD, payload);
94         return setupClient().put(url, payload, buildHeaders(transId), mediaType, mediaType);
95     }
96
97
98     /**
99      * Send a POST request to the A&AI.
100      *
101      * @param url - the url
102      * @param transId - transaction ID
103      * @param payload - the XML or JSON payload for the request
104      * @param mimeType - the content type (XML or JSON)
105      * @return ClientResponse
106      */
107     public OperationResult postResource(String url, String payload, String transId, MediaType mediaType) {
108         logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_PAYLOAD, payload);
109         return setupClient().post(url, payload, buildHeaders(transId), mediaType, mediaType);
110     }
111
112
113     /**
114      * Send a DELETE request to the A&AI.
115      *
116      * @param url - the url
117      * @param resourceVersion - the resource-version of the model to delete
118      * @param transId - transaction ID
119      * @return ClientResponse
120      */
121     public OperationResult deleteResource(String url, String resourceVersion, String transId) {
122         URI uri = UriBuilder.fromUri(url).queryParam(RESOURCE_VERSION_PARAM, resourceVersion).build();
123         return setupClient().delete(uri.toString(), buildHeaders(transId), null);
124     }
125
126     /**
127      * Does a GET on a resource to retrieve the resource version, and then DELETE that version.
128      *
129      * @param url - the url
130      * @param transId - transaction ID
131      * @return ClientResponse
132      */
133     public OperationResult getAndDeleteResource(String url, String transId) {
134         // First, GET the model
135         OperationResult getResponse = getResource(url, transId, MediaType.APPLICATION_XML_TYPE);
136         if ((getResponse == null) || (getResponse.getResultCode() != Response.Status.OK.getStatusCode())) {
137             return getResponse;
138         }
139
140         // Delete the model using the resource version in the response
141         String resVersion = null;
142         try {
143             resVersion = getResourceVersion(getResponse);
144         } catch (Exception e) {
145             logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "GET", url, e.getLocalizedMessage());
146             return null;
147         }
148
149         return deleteResource(url, resVersion, transId);
150     }
151
152
153     public boolean useBasicAuth() {
154         return (config.getAaiAuthenticationUser() != null) && (config.getAaiAuthenticationPassword() != null);
155     }
156
157     private RestClient setupClient() {
158         RestClient restClient = new RestClient();
159
160         // @formatter:off
161         restClient.validateServerHostname(false)
162                 .validateServerCertChain(false)
163                 .clientCertFile(config.getAaiKeyStorePath())
164                 .clientCertPassword(config.getAaiKeyStorePassword());
165         // @formatter:on
166
167         if (useBasicAuth()) {
168             restClient.authenticationMode(RestAuthenticationMode.SSL_BASIC);
169             restClient.basicAuthUsername(config.getAaiAuthenticationUser());
170             restClient.basicAuthPassword(config.getAaiAuthenticationPassword());
171         }
172
173         return restClient;
174     }
175
176     /**
177      * Create the HTTP headers required for an A&AI operation (GET/POST/PUT/DELETE)
178      * 
179      * @param transId
180      * @return map of headers
181      */
182     private Map<String, List<String>> buildHeaders(String transId) {
183         MultivaluedMap<String, String> headers = new MultivaluedMapImpl();
184         headers.put(HEADER_TRANS_ID, Collections.singletonList(transId));
185         headers.put(HEADER_FROM_APP_ID, Collections.singletonList(ML_APP_NAME));
186         return headers;
187     }
188
189     private String getResourceVersion(OperationResult getResponse)
190             throws ParserConfigurationException, SAXException, IOException {
191         String respData = getResponse.getResult();
192
193         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
194         factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
195         DocumentBuilder builder = factory.newDocumentBuilder();
196         InputSource is = new InputSource(new StringReader(respData));
197         Document doc = builder.parse(is);
198
199         NodeList nodesList = doc.getDocumentElement().getChildNodes();
200
201         // @formatter:off
202         return IntStream.range(0, nodesList.getLength()).mapToObj(nodesList::item)
203                 .filter(childNode -> childNode.getNodeName().equals(RESOURCE_VERSION_PARAM))
204                 .findFirst()
205                 .map(Node::getTextContent)
206                 .orElse(null);
207         // @formatter:on
208     }
209 }