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.servlet.http.HttpServletResponse;
37 import org.onap.aaf.cadi.CadiException;
38 import org.onap.aaf.cadi.LocatorException;
39 import org.onap.aaf.cadi.SecuritySetter;
40 import org.onap.aaf.cadi.client.EClient;
41 import org.onap.aaf.cadi.client.Future;
42 import org.onap.aaf.cadi.client.Rcli;
43 import org.onap.aaf.misc.env.APIException;
44 import org.onap.aaf.misc.env.Data;
45 import org.onap.aaf.misc.env.Data.TYPE;
46 import org.onap.aaf.misc.env.util.Pool.Pooled;
47 import org.onap.aaf.misc.rosetta.env.RosettaDF;
50 * Low Level Http Client Mechanism. Chances are, you want the high level "HRcli"
51 * for Rosetta Object Translation
56 public class HClient implements EClient<HttpURLConnection> {
58 private ArrayList<Header> headers;
60 private String pathinfo;
62 private String fragment;
63 private Transfer transfer;
64 private SecuritySetter<HttpURLConnection> ss;
65 private HttpURLConnection huc;
66 private int connectTimeout;
68 public HClient(SecuritySetter<HttpURLConnection> ss, URI uri,int connectTimeout) throws LocatorException {
70 throw new LocatorException("No Service available to call");
74 this.connectTimeout = connectTimeout;
75 pathinfo = query = fragment = null;
79 public void setMethod(String meth) {
84 public void setPathInfo(String pathinfo) {
85 this.pathinfo = pathinfo;
89 public void setPayload(Transfer transfer) {
90 this.transfer = transfer;
94 public void addHeader(String tag, String value) {
96 headers = new ArrayList<Header>();
97 headers.add(new Header(tag, value));
101 public void setQueryParams(String q) {
106 public void setFragment(String f) {
111 public void send() throws APIException {
113 // Build URL from given URI plus current Settings
114 if(uri.getPath()==null) {
115 throw new APIException("Invalid URL entered for HClient");
117 StringBuilder pi=null;
118 if(pathinfo!=null) { // additional pathinfo
119 pi = new StringBuilder(uri.getPath());
120 if(!pathinfo.startsWith("/")) {
128 //huc = (HttpURLConnection) url.openConnection();
129 huc = getConnection(uri, pi);
130 huc.setRequestMethod(meth);
135 for (Header d : headers) {
136 huc.addRequestProperty(d.tag, d.value);
138 huc.setDoInput(true);
139 huc.setDoOutput(true);
140 huc.setUseCaches(false);
141 huc.setConnectTimeout(connectTimeout);
143 if (transfer != null) {
144 transfer.transfer(huc.getOutputStream());
146 // TODO other settings? There's a bunch here.
147 } catch (Exception e) {
148 throw new APIException(e);
149 } finally { // ensure all these are reset after sends
154 pathinfo = query = fragment = "";
158 public URI getURI() {
162 public int timeout() {
163 return connectTimeout;
166 protected HttpURLConnection getConnection(URI uri, StringBuilder pi) throws IOException, URISyntaxException {
172 pi==null?uri.getPath():pi.toString(),
175 return (HttpURLConnection) url.openConnection();
178 public abstract class HFuture<T> extends Future<T> {
179 protected HttpURLConnection huc;
180 protected int respCode;
181 protected IOException exception;
182 protected StringBuilder errContent;
184 public HFuture(final HttpURLConnection huc) {
188 protected boolean evalInfo(HttpURLConnection huc) throws APIException, IOException{
189 return respCode == 200;
193 public final boolean get(int timeout) throws CadiException {
195 huc.setReadTimeout(timeout);
196 respCode = huc.getResponseCode();
197 ss.setLastResponse(respCode);
204 } catch (IOException | APIException e) {
205 throw new CadiException(e);
211 private void extractError() {
212 InputStream is = huc.getErrorStream();
215 is = huc.getInputStream();
218 errContent = new StringBuilder();
220 while((c=is.read())>=0) {
221 errContent.append((char)c);
224 } catch (IOException e) {
229 // Typically only used by Read
230 public StringBuilder inputStreamToString(InputStream is) {
231 // Avoids Carriage returns, and is reasonably efficient, given
234 StringBuilder sb = new StringBuilder();
235 Reader rdr = new InputStreamReader(is);
237 char[] buf = new char[256];
239 while ((read = rdr.read(buf)) >= 0) {
240 sb.append(buf, 0, read);
246 } catch (IOException e) {
258 public HttpURLConnection huc() {
262 public IOException exception() {
267 public String header(String tag) {
268 return huc.getHeaderField(tag);
271 public void close() {
279 public <T> Future<T> futureCreate(Class<T> t) {
280 return new HFuture<T>(huc) {
281 public boolean evalInfo(HttpURLConnection huc) {
282 return respCode==201;
286 public String body() {
287 if (errContent != null) {
288 return errContent.toString();
296 public Future<String> futureReadString() {
297 return new HFuture<String>(huc) {
298 public boolean evalInfo(HttpURLConnection huc) throws IOException {
299 if (respCode == 200) {
300 StringBuilder sb = inputStreamToString(huc.getInputStream());
302 value = sb.toString();
310 public String body() {
313 } else if (errContent != null) {
314 return errContent.toString();
323 public <T> Future<T> futureRead(final RosettaDF<T> df, final TYPE type) {
324 return new HFuture<T>(huc) {
325 private Data<T> data;
327 public boolean evalInfo(HttpURLConnection huc) throws APIException, IOException {
328 if (respCode == 200) {
329 data = df.newData().in(type).load(huc.getInputStream());
330 value = data.asObject();
337 public String body() {
340 return data.asString();
341 } catch (APIException e) {
343 } else if (errContent != null) {
344 return errContent.toString();
352 public <T> Future<T> future(final T t) {
353 return new HFuture<T>(huc) {
354 public boolean evalInfo(HttpURLConnection huc) {
355 if (respCode == 200) {
363 public String body() {
364 if (errContent != null) {
365 return errContent.toString();
367 return Integer.toString(respCode);
373 public Future<Void> future(final HttpServletResponse resp, final int expected) throws APIException {
374 return new HFuture<Void>(huc) {
375 public boolean evalInfo(HttpURLConnection huc) throws IOException, APIException {
376 resp.setStatus(respCode);
379 OutputStream os = resp.getOutputStream();
380 if(respCode==expected) {
381 is = huc.getInputStream();
383 Pooled<byte[]> pbuff = Rcli.buffPool.get();
385 while((read=is.read(pbuff.content))>=0) {
386 os.write(pbuff.content,0,read);
393 is = huc.getErrorStream();
395 is = huc.getInputStream();
398 errContent = new StringBuilder();
399 Pooled<byte[]> pbuff = Rcli.buffPool.get();
401 while((read=is.read(pbuff.content))>=0) {
402 os.write(pbuff.content,0,read);
413 public String body() {
414 return errContent==null?null:errContent.toString();
419 private static class Header {
420 public final String tag;
421 public final String value;
423 public Header(String t, String v) {
428 public String toString() {
429 return tag + '=' + value;
433 public String toString() {
434 return "HttpURLConnection Client configured to " + uri.toString();