Add JUnit for direct Sonar Nexus REST interface
[policy/engine.git] / BRMSGateway / src / main / java / org / onap / policy / brms / api / nexus / NexusRestWrapper.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP Policy Engine
4  * ================================================================================
5  * Copyright (C) 2018 Ericsson Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.brms.api.nexus;
22
23 import com.google.gson.Gson;
24
25 import java.net.URI;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import javax.ws.rs.client.Client;
30 import javax.ws.rs.client.ClientBuilder;
31 import javax.ws.rs.client.Invocation.Builder;
32 import javax.ws.rs.core.Response;
33
34 import org.onap.policy.brms.api.nexus.pojo.NexusArtifact;
35 import org.onap.policy.brms.api.nexus.pojo.NexusRepository;
36 import org.onap.policy.brms.api.nexus.pojo.NexusSearchResult;
37 import org.onap.policy.common.logging.flexlogger.FlexLogger;
38 import org.onap.policy.common.logging.flexlogger.Logger;
39
40 /**
41  * The Class NexusRestWrapper provides a Java API to a Nexus repository, wrapping the Nexus REST interface.
42  */
43 public class NexusRestWrapper {
44     private static final Logger LOGGER = FlexLogger.getLogger(NexusRestWrapper.class.getName());
45
46     // A web client for issuing REST requests to the Nexus server
47     private final Client client;
48
49     // The URL of the Nexus server
50     private final String nexusServerUrl;
51
52     // Credentials for Nexus server logins
53     private String nexusUser;
54     private String nexusPassword;
55
56     /**
57      * Instantiates a new Nexus REST agent with credentials.
58      *
59      * @param nexusServerUrl the URL of the Nexus server as a string
60      * @param nexusUser the Nexus userid
61      * @param nexusPassword the Nexus password
62      * @throws NexusRestWrapperException on parameter exceptions
63      */
64     public NexusRestWrapper(final String nexusServerUrl, final String nexusUser, final String nexusPassword)
65                     throws NexusRestWrapperException {
66         LOGGER.trace("new NexusRestWrapper: nexusServerUrl=" + nexusServerUrl);
67
68         if (isNullOrBlank(nexusServerUrl)) {
69             throw new NexusRestWrapperException("nexusServerUrl must be specified for the Nexus server");
70         }
71
72         if ((isNullOrBlank(nexusUser) && !isNullOrBlank(nexusPassword))
73                         || (!isNullOrBlank(nexusUser) && isNullOrBlank(nexusPassword))) {
74             throw new NexusRestWrapperException(
75                             "if either nexusUser or nexusPassword are specified, both must be specified");
76         }
77
78         this.nexusServerUrl = nexusServerUrl;
79         this.nexusUser = nexusUser;
80         this.nexusPassword = nexusPassword;
81
82         // Create a client for RST calls towards the Nexus server
83         client = ClientBuilder.newClient();
84
85         LOGGER.trace("NexusRestWrapper created: nexusServerUrl=" + nexusServerUrl);
86     }
87
88     /**
89      * Close the REST client.
90      */
91     public void close() {
92         LOGGER.trace("NexusRestWrapper closing: url=" + nexusServerUrl);
93
94         // Close the web client
95         client.close();
96
97         LOGGER.trace("NexusRestWrapper closed: url=" + nexusServerUrl);
98     }
99
100     /**
101      * Find an artifact in the Nexus server.
102      *
103      * @param searchParameters
104      *        the search parameters to use for the search
105      * @return the list of artifacts found that match the requested artifact
106      * @throws NexusRestWrapperException
107      *         Exceptions accessing the Nexus server
108      */
109     public NexusSearchResult findArtifact(final NexusRestSearchParameters searchParameters)
110                     throws NexusRestWrapperException {
111         LOGGER.trace("new search with search parameters: " + searchParameters);
112
113         if (null == searchParameters) {
114             throw new NexusRestWrapperException("searchParameters may not be null");
115         }
116
117         // Issue the REST request to perform the search
118         URI searchUri = searchParameters.getSearchUri(nexusServerUrl);
119
120         LOGGER.debug("search URI is: " + searchUri.toString());
121
122         // Compose the REST request
123         Builder requestBuilder = client.target(searchUri).request("application/json");
124         getAuthorizationHeader(requestBuilder);
125
126         // Issue the REST request
127         Response response = null;
128         try {
129             response = requestBuilder.get();
130         } catch (Exception e) {
131             String message = "search to URI " + searchUri.toString() + " failed with message: " + e.getMessage();
132             LOGGER.warn(message, e);
133             throw new NexusRestWrapperException(message, e);
134         }
135
136         LOGGER.debug("search response is: " + response.toString());
137
138         // Check the HTTP response code for the search
139         if (Response.Status.OK.getStatusCode() != response.getStatus()) {
140             String message = "search to URI " + searchUri.toString() + " failed, response was: " + response.toString();
141             LOGGER.warn(message);
142             throw new NexusRestWrapperException(message);
143         }
144
145         try {
146             // Get the JSON string with the the search result
147             String responseString = response.readEntity(String.class);
148
149             // Parse the returned JSON into result POJOs
150             NexusSearchResult searchResult = new Gson().fromJson(responseString, NexusSearchResult.class);
151
152             // We now need to expand the release and snapshot URL paths for each artifact
153             expandArtifactUrlPaths(searchResult);
154
155             return searchResult;
156         } catch (Exception e) {
157             String message = "processing of result from query to Nexus failed with message: " + e.getMessage();
158             LOGGER.warn(message, e);
159             throw new NexusRestWrapperException(message, e);
160         }
161     }
162
163     /**
164      * Get the authorisation header for the user name and password.
165      * @param requestBuilder the request builder to add authorisation to
166      * @return the authorisation header
167      */
168     private Builder getAuthorizationHeader(Builder requestBuilder) {
169         if (null != nexusUser && null != nexusPassword) {
170             String userPassString = nexusUser + ":" + nexusPassword;
171             requestBuilder.header("Authorization", "Basic "
172                             + java.util.Base64.getEncoder().encodeToString(userPassString.getBytes()));
173         }
174
175         return requestBuilder;
176     }
177
178     /**
179      * Use the Repository URLs in the search result to create a release and snapshot URL path for each artifact.
180      * @param searchResult the results of a Nexus server search
181      */
182     private void expandArtifactUrlPaths(NexusSearchResult searchResult) {
183         // Create a map of repositories for doing lookups
184         Map<String, NexusRepository> repositoryMap = new HashMap<>();
185
186         for (NexusRepository repository : searchResult.getRepoDetailsList()) {
187             repositoryMap.put(repository.getRepositoryId(), repository);
188         }
189
190         for (NexusArtifact artifact : searchResult.getArtifactList()) {
191             artifact.setUrlPath(composeArtifactUrlPath(repositoryMap, artifact));
192         }
193     }
194
195     /**
196      * Compose an artifact URL path using the repository and artifact details for the artifact.
197      * @param repositoryMap the available repositories
198      * @param artifact the artifact
199      * @return the URL path
200      */
201     private String composeArtifactUrlPath(Map<String, NexusRepository> repositoryMap, NexusArtifact artifact) {
202         // We always have one hit
203         NexusRepository repository = repositoryMap.get(artifact.getArtifactHits().get(0).getRepositoryId());
204
205         return new StringBuilder()
206                         .append(repository.getRepositoryUrl())
207                         .append("/content/")
208                         .append(artifact.getGroupId().replace('.', '/'))
209                         .append('/')
210                         .append(artifact.getArtifactId())
211                         .append('/')
212                         .append(artifact.getVersion())
213                         .append('/')
214                         .append(artifact.getArtifactId())
215                         .append('-')
216                         .append(artifact.getVersion())
217                         .toString();
218     }
219
220     /**
221      * Check if a string is null or all white space.
222      */
223     private boolean isNullOrBlank(final String parameter) {
224         return null == parameter || parameter.trim().isEmpty();
225     }
226 }