2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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====================================================
22 package org.onap.aaf.cadi.http;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.io.OutputStream;
28 import java.io.Reader;
29 import java.net.HttpURLConnection;
31 import java.net.URISyntaxException;
33 import java.util.ArrayList;
35 import javax.net.ssl.SSLException;
36 import javax.net.ssl.SSLHandshakeException;
37 import javax.servlet.http.HttpServletResponse;
39 import org.onap.aaf.cadi.CadiException;
40 import org.onap.aaf.cadi.LocatorException;
41 import org.onap.aaf.cadi.SecuritySetter;
42 import org.onap.aaf.cadi.client.EClient;
43 import org.onap.aaf.cadi.client.Future;
44 import org.onap.aaf.cadi.client.Rcli;
45 import org.onap.aaf.misc.env.APIException;
46 import org.onap.aaf.misc.env.Data;
47 import org.onap.aaf.misc.env.Data.TYPE;
48 import org.onap.aaf.misc.env.util.Pool.Pooled;
49 import org.onap.aaf.misc.rosetta.env.RosettaDF;
52 * Low Level Http Client Mechanism. Chances are, you want the high level "HRcli"
53 * for Rosetta Object Translation
58 public class HClient implements EClient<HttpURLConnection> {
60 private ArrayList<Header> headers;
62 private String pathinfo;
64 private String fragment;
65 private Transfer transfer;
66 private SecuritySetter<HttpURLConnection> ss;
67 private HttpURLConnection huc;
68 private int connectTimeout;
70 public HClient(SecuritySetter<HttpURLConnection> ss, URI uri,int connectTimeout) throws LocatorException {
72 throw new LocatorException("No Service available to call");
76 this.connectTimeout = connectTimeout;
77 pathinfo = query = fragment = null;
81 public void setMethod(String meth) {
86 public void setPathInfo(String pathinfo) {
87 this.pathinfo = pathinfo;
91 public void setPayload(Transfer transfer) {
92 this.transfer = transfer;
96 public void addHeader(String tag, String value) {
98 headers = new ArrayList<>();
99 headers.add(new Header(tag, value));
103 public void setQueryParams(String q) {
108 public void setFragment(String f) {
113 public void send() throws APIException {
114 // Build URL from given URI plus current Settings
115 if (uri.getPath()==null) {
116 throw new APIException("Invalid URL entered for HClient");
118 StringBuilder pi=null;
119 if (pathinfo!=null) { // additional pathinfo
120 pi = new StringBuilder(uri.getPath());
121 if (!pathinfo.startsWith("/")) {
131 pi==null?uri.getPath():pi.toString(),
132 query==null?uri.getQuery():query,
133 fragment==null?uri.getFragment():fragment
135 huc = getConnection(sendURI, pi);
136 huc.setRequestMethod(meth);
141 for (Header d : headers) {
142 huc.addRequestProperty(d.tag, d.value);
144 huc.setDoInput(true);
145 huc.setDoOutput(true);
146 huc.setUseCaches(false);
147 huc.setConnectTimeout(connectTimeout);
149 if (transfer != null) {
150 transfer.transfer(huc.getOutputStream());
152 // TODO other settings? There's a bunch here.
153 } catch (APIException e) {
155 } catch (Exception e) {
157 throw new APIException("Cannot connect to Root URI: '" + uri.toString() + '\'',e);
159 throw new APIException("Cannot connect to '" + sendURI.toString() + "' (Root URI: '" + uri.toString() + "')",e);
161 } finally { // ensure all these are reset after sends
166 pathinfo = query = fragment = "";
170 public URI getURI() {
174 public void setURI(URI uri) {
178 public int timeout() {
179 return connectTimeout;
182 protected HttpURLConnection getConnection(URI uri, StringBuilder pi) throws IOException, URISyntaxException {
186 pi==null?uri.getPath():pi.toString(),
189 return (HttpURLConnection) url.openConnection();
192 public abstract class HFuture<T> extends Future<T> {
193 protected HttpURLConnection huc;
194 protected int respCode;
195 protected IOException exception;
196 protected StringBuilder errContent;
198 public HFuture(final HttpURLConnection huc) {
202 protected boolean evalInfo(HttpURLConnection huc) throws APIException, IOException{
203 return respCode == 200;
207 public final boolean get(int timeout) throws CadiException {
209 huc.setReadTimeout(timeout);
210 respCode = huc.getResponseCode();
211 ss.setLastResponse(respCode);
218 } catch (IOException | APIException e) {
219 throw new CadiException(e);
225 private void extractError() {
226 InputStream is = huc.getErrorStream();
229 is = huc.getInputStream();
232 errContent = new StringBuilder();
234 while ((c=is.read())>=0) {
235 errContent.append((char)c);
238 } catch (IOException e) {
243 // Typically only used by Read
244 public StringBuilder inputStreamToString(InputStream is) {
245 // Avoids Carriage returns, and is reasonably efficient, given
248 StringBuilder sb = new StringBuilder();
249 Reader rdr = new InputStreamReader(is);
251 char[] buf = new char[256];
253 while ((read = rdr.read(buf)) >= 0) {
254 sb.append(buf, 0, read);
260 } catch (IOException e) {
272 public HttpURLConnection huc() {
276 public IOException exception() {
281 public String header(String tag) {
282 return huc.getHeaderField(tag);
285 public void close() {
293 public <T> Future<T> futureCreate(Class<T> t) {
294 return new HFuture<T>(huc) {
295 public boolean evalInfo(HttpURLConnection huc) {
296 return respCode==201;
300 public String body() {
301 if (errContent != null) {
302 return errContent.toString();
310 public Future<String> futureReadString() {
311 return new HFuture<String>(huc) {
312 public boolean evalInfo(HttpURLConnection huc) throws IOException {
313 if (respCode == 200) {
314 StringBuilder sb = inputStreamToString(huc.getInputStream());
316 value = sb.toString();
324 public String body() {
327 } else if (errContent != null) {
328 return errContent.toString();
337 public <T> Future<T> futureRead(final RosettaDF<T> df, final TYPE type) {
338 return new HFuture<T>(huc) {
339 private Data<T> data;
341 public boolean evalInfo(HttpURLConnection huc) throws APIException, IOException {
342 if (respCode == 200) {
343 data = df.newData().in(type).load(huc.getInputStream());
344 value = data.asObject();
351 public String body() {
354 return data.asString();
355 } catch (APIException e) {
357 } else if (errContent != null) {
358 return errContent.toString();
366 public <T> Future<T> future(final T t) {
367 return new HFuture<T>(huc) {
368 public boolean evalInfo(HttpURLConnection huc) {
369 if (respCode == 200) {
377 public String body() {
378 if (errContent != null) {
379 return errContent.toString();
381 return Integer.toString(respCode);
387 public Future<Void> future(final HttpServletResponse resp, final int expected) throws APIException {
388 return new HFuture<Void>(huc) {
389 public boolean evalInfo(HttpURLConnection huc) throws IOException, APIException {
390 resp.setStatus(respCode);
393 OutputStream os = resp.getOutputStream();
394 if (respCode==expected) {
395 is = huc.getInputStream();
397 Pooled<byte[]> pbuff = Rcli.buffPool.get();
399 while ((read=is.read(pbuff.content))>=0) {
400 os.write(pbuff.content,0,read);
407 is = huc.getErrorStream();
409 is = huc.getInputStream();
412 errContent = new StringBuilder();
413 Pooled<byte[]> pbuff = Rcli.buffPool.get();
415 while ((read=is.read(pbuff.content))>=0) {
416 os.write(pbuff.content,0,read);
427 public String body() {
428 return errContent==null?null:errContent.toString();
433 private static class Header {
434 public final String tag;
435 public final String value;
437 public Header(String t, String v) {
442 public String toString() {
443 return tag + '=' + value;
447 public String toString() {
448 return "HttpURLConnection Client configured to " + uri.toString();