Implement Sonar Nexus REST interface directly
[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.
58      *
59      * @param nexusServerUrl the URL of the Nexus server as a string
60      * @throws NexusRestWrapperException on errors on the Nexus server URL
61      */
62     public NexusRestWrapper(final String nexusServerUrl) throws NexusRestWrapperException {
63         LOGGER.trace("new NexusRestWrapper: nexusServerUrl=" + nexusServerUrl);
64
65         if (isNullOrBlank(nexusServerUrl)) {
66             throw new NexusRestWrapperException("nexusServerUrl must be specified for the Nexus server");
67         }
68
69         this.nexusServerUrl = nexusServerUrl;
70
71         // Create a client for RST calls towards the Nexus server
72         client = ClientBuilder.newClient();
73     }
74
75     /**
76      * Instantiates a new Nexus REST agent with credentials.
77      *
78      * @param nexusServerUrl the URL of the Nexus server as a string
79      * @param nexusUser the Nexus userid
80      * @param nexusPassword the Nexus password
81      * @throws NexusRestWrapperException on parameter exceptions
82      */
83     public NexusRestWrapper(final String nexusServerUrl, final String nexusUser, final String nexusPassword)
84             throws NexusRestWrapperException {
85         LOGGER.trace("new NexusRestWrapper: nexusServerUrl=" + nexusServerUrl);
86
87         if (isNullOrBlank(nexusServerUrl)) {
88             throw new NexusRestWrapperException("nexusServerUrl must be specified for the Nexus server");
89         }
90
91         if (isNullOrBlank(nexusUser) || isNullOrBlank(nexusPassword)) {
92             throw new NexusRestWrapperException("nexuusUser and nexusPassword must both be specified");
93         }
94
95         this.nexusServerUrl = nexusServerUrl;
96         this.nexusUser = nexusUser;
97         this.nexusPassword = nexusPassword;
98
99         // Create a client for RST calls towards the Nexus server
100         client = ClientBuilder.newClient();
101
102         LOGGER.trace("NexusRestWrapper created: nexusServerUrl=" + nexusServerUrl);
103     }
104
105     /**
106      * Close the REST client.
107      */
108     public void close() {
109         LOGGER.trace("NexusRestWrapper closing: url=" + nexusServerUrl);
110
111         // Close the web client
112         client.close();
113
114         LOGGER.trace("NexusRestWrapper closed: url=" + nexusServerUrl);
115     }
116
117     /**
118      * Find an artifact in the Nexus server.
119      *
120      * @param searchParameters
121      *        the search parameters to use for the search
122      * @return the list of artifacts found that match the requested artifact
123      * @throws NexusRestWrapperException
124      *         Exceptions accessing the Nexus server
125      */
126     public NexusSearchResult findArtifact(final NexusRestSearchParameters searchParameters)
127             throws NexusRestWrapperException {
128
129         LOGGER.trace("new search with search parameters: " + searchParameters);
130
131         // Issue the REST request to perform the search
132         URI searchUri = searchParameters.getSearchUri(nexusServerUrl);
133
134         LOGGER.debug("search URI is: " + searchUri.toString());
135
136         // Compose the REST request
137         Builder requestBuilder = client.target(searchUri).request("application/json");
138         getAuthorizationHeader(requestBuilder);
139
140         // Issue the REST request
141         Response response = requestBuilder.get();
142
143         LOGGER.debug("search response is: " + response.toString());
144
145         // Check the HTTP response code for the search
146         if (Response.Status.OK.getStatusCode() != response.getStatus()) {
147             LOGGER.warn("search to URI " + searchUri.toString() + "failed, response was: " + response.toString());
148             throw new NexusRestWrapperException("query to Nexus failed with message: " + response.toString());
149         }
150
151         try {
152             // Get the JSON string with the the search result
153             String responseString = response.readEntity(String.class);
154
155             // Parse the returned JSON into result POJOs
156             NexusSearchResult searchResult = new Gson().fromJson(responseString, NexusSearchResult.class);
157
158             // We now need to expand the release and snapshot URL paths for each artifact
159             expandArtifactUrlPaths(searchResult);
160
161             return searchResult;
162         } catch (Exception e) {
163             LOGGER.warn("processing of result from search to URI " + searchUri
164                     + " failed with message " + e.getMessage());
165             throw new NexusRestWrapperException(
166                     "processing of result from query to Nexus failed with message: " + e.getMessage(), e);
167         }
168     }
169
170     /**
171      * Get the authorisation header for the user name and password.
172      * @param requestBuilder the request builder to add authorization to
173      * @return the authorisation header
174      */
175     private Builder getAuthorizationHeader(Builder requestBuilder) {
176         if (null != nexusUser && null != nexusPassword) {
177             String userPassString = nexusUser + ":" + nexusPassword;
178             requestBuilder.header("Authorization", "Basic "
179                     + java.util.Base64.getEncoder().encodeToString(userPassString.getBytes()));
180         }
181
182         return requestBuilder;
183     }
184
185     /**
186      * Use the Repository URLs in the search result to create a release and snapshot URL path for each artifact.
187      * @param searchResult the results of a Nexus server search
188      */
189     private void expandArtifactUrlPaths(NexusSearchResult searchResult) {
190         // Create a map of repositories for doing lookups
191         Map<String, NexusRepository> repositoryMap = new HashMap<>();
192
193         for (NexusRepository repository : searchResult.getRepoDetailsList()) {
194             repositoryMap.put(repository.getRepositoryId(), repository);
195         }
196
197         for (NexusArtifact artifact : searchResult.getArtifactList()) {
198             artifact.setUrlPath(composeArtifactUrlPath(repositoryMap, artifact));
199         }
200     }
201
202     /**
203      * Compose an artifact URL path using the repository and artifact details for the artifact.
204      * @param repositoryMap the available repositories
205      * @param artifact the artifact
206      * @return the URL path
207      */
208     private String composeArtifactUrlPath(Map<String, NexusRepository> repositoryMap, NexusArtifact artifact) {
209         // We always have one hit
210         NexusRepository repository = repositoryMap.get(artifact.getArtifactHits().get(0).getRepositoryId());
211
212         return new StringBuilder()
213                 .append(repository.getRepositoryUrl())
214                 .append("/content/")
215                 .append(artifact.getGroupId().replace('.', '/'))
216                 .append('/')
217                 .append(artifact.getArtifactId())
218                 .append('/')
219                 .append(artifact.getVersion())
220                 .append('/')
221                 .append(artifact.getArtifactId())
222                 .append('-')
223                 .append(artifact.getVersion())
224                 .toString();
225     }
226
227     /**
228      * Check if a string is null or all white space.
229      */
230     private boolean isNullOrBlank(final String parameter) {
231         return null == parameter || parameter.trim().isEmpty();
232     }
233 }