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;
32 import java.util.ArrayList;
34 import javax.servlet.http.HttpServletResponse;
36 import org.onap.aaf.cadi.CadiException;
37 import org.onap.aaf.cadi.LocatorException;
38 import org.onap.aaf.cadi.SecuritySetter;
39 import org.onap.aaf.cadi.client.EClient;
40 import org.onap.aaf.cadi.client.Future;
41 import org.onap.aaf.cadi.client.Rcli;
42 import org.onap.aaf.misc.env.APIException;
43 import org.onap.aaf.misc.env.Data;
44 import org.onap.aaf.misc.env.Data.TYPE;
45 import org.onap.aaf.misc.env.util.Pool.Pooled;
46 import org.onap.aaf.misc.rosetta.env.RosettaDF;
49 * Low Level Http Client Mechanism. Chances are, you want the high level "HRcli"
50 * for Rosetta Object Translation
55 public class HClient implements EClient<HttpURLConnection> {
57 private ArrayList<Header> headers;
59 private String pathinfo;
61 private String fragment;
62 private Transfer transfer;
63 private SecuritySetter<HttpURLConnection> ss;
64 private HttpURLConnection huc;
65 private int connectTimeout;
67 public HClient(SecuritySetter<HttpURLConnection> ss, URI uri,int connectTimeout) throws LocatorException {
69 throw new LocatorException("No Service available to call");
73 this.connectTimeout = connectTimeout;
74 pathinfo = query = fragment = null;
78 public void setMethod(String meth) {
83 public void setPathInfo(String pathinfo) {
84 this.pathinfo = pathinfo;
88 public void setPayload(Transfer transfer) {
89 this.transfer = transfer;
93 public void addHeader(String tag, String value) {
95 headers = new ArrayList<Header>();
96 headers.add(new Header(tag, value));
100 public void setQueryParams(String q) {
105 public void setFragment(String f) {
110 public void send() throws APIException {
112 // Build URL from given URI plus current Settings
113 if(uri.getPath()==null) {
114 throw new APIException("Invalid URL entered for HClient");
116 StringBuilder pi=null;
117 if(pathinfo!=null) { // additional pathinfo
118 pi = new StringBuilder(uri.getPath());
119 if(!pathinfo.startsWith("/")) {
129 pi==null?uri.getPath():pi.toString(),
135 huc = (HttpURLConnection) url.openConnection();
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 (Exception e) {
154 throw new APIException(e);
155 } finally { // ensure all these are reset after sends
160 pathinfo = query = fragment = "";
164 public URI getURI() {
168 public int timeout() {
169 return connectTimeout;
172 public abstract class HFuture<T> extends Future<T> {
173 protected HttpURLConnection huc;
174 protected int respCode;
175 protected String respMessage;
176 protected IOException exception;
177 protected StringBuilder errContent;
179 public HFuture(final HttpURLConnection huc) {
183 protected boolean evalInfo(HttpURLConnection huc) throws APIException, IOException{
184 return respCode == 200;
188 public final boolean get(int timeout) throws CadiException {
190 huc.setReadTimeout(timeout);
191 respCode = huc.getResponseCode();
192 ss.setLastResponse(respCode);
199 } catch (IOException | APIException e) {
200 throw new CadiException(e);
206 private void extractError() {
207 InputStream is = huc.getErrorStream();
210 is = huc.getInputStream();
213 errContent = new StringBuilder();
215 while((c=is.read())>=0) {
216 errContent.append((char)c);
219 } catch (IOException e) {
224 // Typically only used by Read
225 public StringBuilder inputStreamToString(InputStream is) {
226 // Avoids Carriage returns, and is reasonably efficient, given
229 StringBuilder sb = new StringBuilder();
230 Reader rdr = new InputStreamReader(is);
232 char[] buf = new char[256];
234 while ((read = rdr.read(buf)) >= 0) {
235 sb.append(buf, 0, read);
241 } catch (IOException e) {
253 public HttpURLConnection huc() {
257 public IOException exception() {
261 public String respMessage() {
266 public String header(String tag) {
267 return huc.getHeaderField(tag);
270 public void close() {
278 public <T> Future<T> futureCreate(Class<T> t) {
279 return new HFuture<T>(huc) {
280 public boolean evalInfo(HttpURLConnection huc) {
281 return respCode==201;
285 public String body() {
286 if (errContent != null) {
287 return errContent.toString();
289 } else if (respMessage != null) {
298 public Future<String> futureReadString() {
299 return new HFuture<String>(huc) {
300 public boolean evalInfo(HttpURLConnection huc) throws IOException {
301 if (respCode == 200) {
302 StringBuilder sb = inputStreamToString(huc.getInputStream());
304 value = sb.toString();
312 public String body() {
315 } else if (errContent != null) {
316 return errContent.toString();
317 } else if (respMessage != null) {
327 public <T> Future<T> futureRead(final RosettaDF<T> df, final TYPE type) {
328 return new HFuture<T>(huc) {
329 private Data<T> data;
331 public boolean evalInfo(HttpURLConnection huc) throws APIException, IOException {
332 if (respCode == 200) {
333 data = df.newData().in(type).load(huc.getInputStream());
334 value = data.asObject();
341 public String body() {
344 return data.asString();
345 } catch (APIException e) {
347 } else if (errContent != null) {
348 return errContent.toString();
349 } else if (respMessage != null) {
358 public <T> Future<T> future(final T t) {
359 return new HFuture<T>(huc) {
360 public boolean evalInfo(HttpURLConnection huc) {
361 if (respCode == 200) {
369 public String body() {
370 if (errContent != null) {
371 return errContent.toString();
372 } else if (respMessage != null) {
375 return Integer.toString(respCode);
381 public Future<Void> future(final HttpServletResponse resp, final int expected) throws APIException {
382 return new HFuture<Void>(huc) {
383 public boolean evalInfo(HttpURLConnection huc) throws IOException, APIException {
384 resp.setStatus(respCode);
387 OutputStream os = resp.getOutputStream();
388 if(respCode==expected) {
389 is = huc.getInputStream();
391 Pooled<byte[]> pbuff = Rcli.buffPool.get();
393 while((read=is.read(pbuff.content))>=0) {
394 os.write(pbuff.content,0,read);
401 is = huc.getErrorStream();
403 is = huc.getInputStream();
406 errContent = new StringBuilder();
407 Pooled<byte[]> pbuff = Rcli.buffPool.get();
409 while((read=is.read(pbuff.content))>=0) {
410 os.write(pbuff.content,0,read);
421 public String body() {
422 return errContent==null?respMessage:errContent.toString();
427 private static class Header {
428 public final String tag;
429 public final String value;
431 public Header(String t, String v) {
436 public String toString() {
437 return tag + '=' + value;
441 public String toString() {
442 return "HttpURLConnection Client configured to " + uri.toString();