aboutsummaryrefslogtreecommitdiffstats
path: root/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/openecomp/dcae/dmaapbc/client/SimpleRestClientBase.java
blob: 7868d8c8c16d7d19ba2dc9460e507d2260ba7f2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/*-
 * ================================================================================
 * DCAE DMaaP Bus Controller REST Client
 * ================================================================================
 * Copyright (C) 2017 AT&T Intellectual Property
 * ================================================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ================================================================================
 */
package org.openecomp.dcae.dmaapbc.client;

import java.io.IOException;
import java.net.URI;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Provides a basic client to access a REST endpoint, optionally using HTTP
 * basic authentication.
 * 
 * Caveat: If HTTPS access is used and the server uses a self-signed
 * certificate, the local trust store must be extended appropriately. The client
 * throws exceptions if the JVM cannot validate the server certificate.
 */
public class SimpleRestClientBase {

	private static Logger logger = LoggerFactory.getLogger(SimpleRestClientBase.class);

	/**
	 * Credentials for HTTP basic authentication (optional).
	 */
	private final String username;
	private final String password;

	/**
	 * Timeouts (optional)
	 */
	private Integer connectTimeoutMs = null;
	private Integer connectionRequestTimeoutMs = null;
	private Integer socketTimeoutMs = null;

	/**
	 * Constructs a client that does not use any authentication and uses Apache
	 * HTTPD client default values for timeouts.
	 */
	public SimpleRestClientBase() {
		this(null, null, null, null, null);
	}

	/**
	 * Convenience constructor to build a client that uses the specified
	 * username and password for basic HTTP authentication on all requests. In
	 * other words, this client pre-emptively sends the "Basic" header instead
	 * of first trying the request without, failing, negotiating, then sending
	 * with credentials.
	 * 
	 * @param username
	 *            User name for basic HTTP authentication.
	 * @param password
	 *            Password for basic HTTP authentication.
	 */
	public SimpleRestClientBase(final String username, final String password) {
		this(username, password, null, null, null);
	}

	/**
	 * Convenience constructor to build a client that uses the specified
	 * timeouts on all requests.
	 *
	 * @param connectTimeoutMs
	 *            Connection timeout, in milliseconds
	 * @param connectionRequestTimeoutMs
	 *            Connection request timeout, in milliseconds
	 * @param socketTimeoutMs
	 *            Socket timeout, in milliseconds
	 */
	public SimpleRestClientBase(final Integer connectTimeoutMs, final Integer connectionRequestTimeoutMs,
			final Integer socketTimeoutMs) {
		this(null, null, connectTimeoutMs, connectionRequestTimeoutMs, socketTimeoutMs);
	}

	/**
	 * Constructs a client with the specified credentials and timeout values.
	 * 
	 * @param username
	 *            User name for basic HTTP authentication; ignored if null
	 * @param password
	 *            Password for basic HTTP authentication; ignored if null
	 * @param connectTimeoutMs
	 *            ignored if null
	 * @param connectionRequestTimeoutMs
	 *            ignored if null
	 * @param socketTimeoutMs
	 *            ignored if null
	 */
	public SimpleRestClientBase(final String username, final String password, final Integer connectTimeoutMs,
			final Integer connectionRequestTimeoutMs, final Integer socketTimeoutMs) {
		this.username = username;
		this.password = password;
		this.connectTimeoutMs = null;
		this.connectionRequestTimeoutMs = null;
		this.socketTimeoutMs = null;
	}

	/**
	 * Constructs and sends a GET request for the URI.
	 * 
	 * @param uri
	 *            REST endpoint
	 * @return Result of the get
	 * @throws Exception
	 *             On any error
	 */
	public HttpStatusAndResponse<String> getRestContent(final URI uri) throws Exception {
		HttpGet httpGet = new HttpGet(uri);
		return doRestRequest(httpGet);
	}

	/**
	 * Constructs and sends a POST request using the specified body.
	 * 
	 * @param uri
	 *            REST endpoint
	 * @param json
	 *            Content to post
	 * @return Result of the post; null if an error happens
	 * @throws Exception
	 *             On any error
	 */
	public HttpStatusAndResponse<String> postRestContent(final URI uri, final String json) throws Exception {
		HttpPost httpPost = new HttpPost(uri);
		StringEntity postEntity = new StringEntity(json, ContentType.create("application/json", Consts.UTF_8));
		httpPost.setEntity(postEntity);
		return doRestRequest(httpPost);
	}

	/**
	 * Constructs and sends a PUT request using the specified body.
	 * 
	 * @param uri
	 *            REST endpoint
	 * @param json
	 *            Content to put
	 * @return Result of the put; null if an error happens
	 * @throws Exception
	 *             On any error
	 */
	public HttpStatusAndResponse<String> putRestContent(final URI uri, final String json) throws Exception {
		HttpPut httpPut = new HttpPut(uri);
		StringEntity postEntity = new StringEntity(json, ContentType.create("application/json", Consts.UTF_8));
		httpPut.setEntity(postEntity);
		return doRestRequest(httpPut);
	}

	/**
	 * Constructs and sends a DELETE request for the URI.
	 * 
	 * @param uri
	 *            REST endpoint
	 * @return Result of the get
	 * @throws Exception
	 *             On any error
	 */
	public HttpStatusAndResponse<String> deleteRestContent(final URI uri) throws Exception {
		HttpDelete httpDel = new HttpDelete(uri);
		return doRestRequest(httpDel);
	}

	/**
	 * Executes the specified request and gathers the response.
	 * 
	 * @param request
	 *            HttpGet, HttpPost, etc.
	 * @return Status code and response body
	 * @throws ClientProtocolException
	 *             On HTTP protocol error
	 * @throws IOException
	 *             On read/write error
	 */
	private HttpStatusAndResponse<String> doRestRequest(final HttpRequestBase request)
			throws ClientProtocolException, IOException {

		// Set up authentication if needed
		final HttpClientContext context = HttpClientContext.create();
		if (this.username != null || this.password != null) {
			UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(this.username, this.password);
			CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
			credentialsProvider.setCredentials(AuthScope.ANY, credentials);
			context.setCredentialsProvider(credentialsProvider);

			HttpHost host = new HttpHost(request.getURI().getHost(), request.getURI().getPort(),
					request.getURI().getScheme());
			AuthCache authCache = new BasicAuthCache();
			authCache.put(host, new BasicScheme());
			context.setAuthCache(authCache);
		}
		final Builder requestConfigBuilder = RequestConfig.custom();
		if (connectionRequestTimeoutMs != null)
			requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeoutMs);
		if (connectTimeoutMs != null)
			requestConfigBuilder.setConnectTimeout(connectTimeoutMs);
		if (socketTimeoutMs != null)
			requestConfigBuilder.setSocketTimeout(socketTimeoutMs);
		RequestConfig requestConfig = requestConfigBuilder.build();
		final CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
		CloseableHttpResponse response = null;
		String responseJson = null;
		try {
			response = httpClient.execute(request, context);
			// Some methods return non-200 on success
			logger.debug("doRestRequest: status is {}", response.getStatusLine());
			HttpEntity entity = response.getEntity();
			// This is common; don't warn
			if (entity == null) {
				logger.debug("doRestRequest: Entity is null");
			} else {
				// entity content length is never set;
				// this naively tries to read everything.
				responseJson = EntityUtils.toString(entity);
				EntityUtils.consume(entity);
				// Don't give back empty string;
				// it has no more meaning than null.
				if (responseJson.length() == 0)
					responseJson = null;
			}
		} finally {
			if (response != null)
				response.close();
		}
		if (response == null)
			return null;
		return new HttpStatusAndResponse<String>(response.getStatusLine().getStatusCode(), responseJson);
	}

	/**
	 * Basic test invocation.
	 * 
	 * @param args
	 *            Expect 1 argument, the URL of a REST endpoint.
	 * @throws Exception
	 *             if anything goes wrong
	 */
	public static void main(String[] args) throws Exception {
		if (args.length != 1)
			throw new IllegalArgumentException("Expect 1 argument: REST URL for GET");
		SimpleRestClientBase client = new SimpleRestClientBase();
		URIBuilder uriBuilder = new URIBuilder(args[0]);
		URI uri = uriBuilder.build();
		HttpStatusAndResponse<String> hsr = client.getRestContent(uri);
		System.out.println("Response code is " + hsr.getStatusCode());
		System.out.println(hsr.getResponseString());
		System.out.println("main ends.");
	}
}