1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * ===========================================================================
\r
7 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * * you may not use this file except in compliance with the License.
\r
9 * * You may obtain a copy of the License at
\r
11 * * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * * Unless required by applicable law or agreed to in writing, software
\r
14 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * * See the License for the specific language governing permissions and
\r
17 * * limitations under the License.
\r
18 * * ============LICENSE_END====================================================
\r
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
23 package org.onap.aaf.cadi.http;
\r
25 import java.io.IOException;
\r
26 import java.io.InputStream;
\r
27 import java.io.InputStreamReader;
\r
28 import java.io.OutputStream;
\r
29 import java.io.Reader;
\r
30 import java.net.HttpURLConnection;
\r
31 import java.net.URI;
\r
32 import java.net.URL;
\r
33 import java.util.ArrayList;
\r
35 import javax.servlet.http.HttpServletResponse;
\r
37 import org.onap.aaf.cadi.CadiException;
\r
38 import org.onap.aaf.cadi.LocatorException;
\r
39 import org.onap.aaf.cadi.SecuritySetter;
\r
40 import org.onap.aaf.cadi.client.EClient;
\r
41 import org.onap.aaf.cadi.client.Future;
\r
42 import org.onap.aaf.cadi.client.Rcli;
\r
44 import org.onap.aaf.inno.env.APIException;
\r
45 import org.onap.aaf.inno.env.Data;
\r
46 import org.onap.aaf.inno.env.Data.TYPE;
\r
47 import org.onap.aaf.inno.env.util.Pool.Pooled;
\r
48 import org.onap.aaf.rosetta.env.RosettaDF;
\r
51 * Low Level Http Client Mechanism. Chances are, you want the high level "HRcli"
\r
52 * for Rosetta Object Translation
\r
56 public class HClient implements EClient<HttpURLConnection> {
\r
58 private ArrayList<Header> headers;
\r
59 private String meth;
\r
60 private String pathinfo;
\r
61 private String query;
\r
62 private String fragment;
\r
63 private Transfer transfer;
\r
64 private SecuritySetter<HttpURLConnection> ss;
\r
65 private HttpURLConnection huc;
\r
66 private int connectTimeout;
\r
68 public HClient(SecuritySetter<HttpURLConnection> ss, URI uri,int connectTimeout) throws LocatorException {
\r
70 throw new LocatorException("No Service available to call");
\r
74 this.connectTimeout = connectTimeout;
\r
75 pathinfo = query = fragment = "";
\r
79 public void setMethod(String meth) {
\r
84 public void setPathInfo(String pathinfo) {
\r
85 this.pathinfo = pathinfo;
\r
89 public void setPayload(Transfer transfer) {
\r
90 this.transfer = transfer;
\r
94 public void addHeader(String tag, String value) {
\r
95 if (headers == null)
\r
96 headers = new ArrayList<Header>();
\r
97 headers.add(new Header(tag, value));
\r
101 public void setQueryParams(String q) {
\r
106 public void setFragment(String f) {
\r
111 public void send() throws APIException {
\r
113 // Build URL from given URI plus current Settings
\r
114 if(uri.getPath()==null) {
\r
115 throw new APIException("Invalid URL entered for HClient");
\r
117 StringBuilder pi = new StringBuilder(uri.getPath());
\r
118 if(!pathinfo.startsWith("/")) {
\r
121 pi.append(pathinfo);
\r
133 huc = (HttpURLConnection) url.openConnection();
\r
135 ss.setSecurity(huc);
\r
137 huc.setRequestMethod(meth);
\r
138 if (headers != null)
\r
139 for (Header d : headers) {
\r
140 huc.addRequestProperty(d.tag, d.value);
\r
142 huc.setDoInput(true);
\r
143 huc.setDoOutput(true);
\r
144 huc.setUseCaches(false);
\r
145 huc.setConnectTimeout(connectTimeout);
\r
147 if (transfer != null) {
\r
148 transfer.transfer(huc.getOutputStream());
\r
150 // TODO other settings? There's a bunch here.
\r
151 } catch (Exception e) {
\r
152 throw new APIException(e);
\r
153 } finally { // ensure all these are reset after sends
\r
154 meth=pathinfo=null;
\r
155 if(headers!=null) {
\r
158 pathinfo = query = fragment = "";
\r
162 public abstract class HFuture<T> extends Future<T> {
\r
163 protected HttpURLConnection huc;
\r
164 protected int respCode;
\r
165 protected String respMessage;
\r
166 protected IOException exception;
\r
167 protected StringBuilder errContent;
\r
169 public HFuture(final HttpURLConnection huc) {
\r
173 protected boolean evalInfo(HttpURLConnection huc) throws APIException, IOException{
\r
174 return respCode == 200;
\r
178 public final boolean get(int timeout) throws CadiException {
\r
180 huc.setReadTimeout(timeout);
\r
181 respCode = huc.getResponseCode();
\r
182 ss.setLastResponse(respCode);
\r
183 if(evalInfo(huc)) {
\r
189 } catch (IOException | APIException e) {
\r
190 throw new CadiException(e);
\r
196 private void extractError() {
\r
197 InputStream is = huc.getErrorStream();
\r
200 is = huc.getInputStream();
\r
203 errContent = new StringBuilder();
\r
205 while((c=is.read())>=0) {
\r
206 errContent.append((char)c);
\r
209 } catch (IOException e) {
\r
214 // Typically only used by Read
\r
215 public StringBuilder inputStreamToString(InputStream is) {
\r
216 // Avoids Carriage returns, and is reasonably efficient, given
\r
217 // the buffer reads.
\r
219 StringBuilder sb = new StringBuilder();
\r
220 Reader rdr = new InputStreamReader(is);
\r
222 char[] buf = new char[256];
\r
224 while ((read = rdr.read(buf)) >= 0) {
\r
225 sb.append(buf, 0, read);
\r
231 } catch (IOException e) {
\r
239 public int code() {
\r
243 public HttpURLConnection huc() {
\r
247 public IOException exception() {
\r
251 public String respMessage() {
\r
252 return respMessage;
\r
256 public String header(String tag) {
\r
257 return huc.getHeaderField(tag);
\r
260 public void close() {
\r
268 public <T> Future<T> futureCreate(Class<T> t) {
\r
269 return new HFuture<T>(huc) {
\r
270 public boolean evalInfo(HttpURLConnection huc) {
\r
271 return respCode==201;
\r
275 public String body() {
\r
276 if (errContent != null) {
\r
277 return errContent.toString();
\r
279 } else if (respMessage != null) {
\r
280 return respMessage;
\r
288 public Future<String> futureReadString() {
\r
289 return new HFuture<String>(huc) {
\r
290 public boolean evalInfo(HttpURLConnection huc) throws IOException {
\r
291 if (respCode == 200) {
\r
292 StringBuilder sb = inputStreamToString(huc.getInputStream());
\r
294 value = sb.toString();
\r
302 public String body() {
\r
303 if (value != null) {
\r
305 } else if (errContent != null) {
\r
306 return errContent.toString();
\r
307 } else if (respMessage != null) {
\r
308 return respMessage;
\r
317 public <T> Future<T> futureRead(final RosettaDF<T> df, final TYPE type) {
\r
318 return new HFuture<T>(huc) {
\r
319 private Data<T> data;
\r
321 public boolean evalInfo(HttpURLConnection huc) throws APIException, IOException {
\r
322 if (respCode == 200) {
\r
323 data = df.newData().in(type).load(huc.getInputStream());
\r
324 value = data.asObject();
\r
331 public String body() {
\r
332 if (data != null) {
\r
334 return data.asString();
\r
335 } catch (APIException e) {
\r
337 } else if (errContent != null) {
\r
338 return errContent.toString();
\r
339 } else if (respMessage != null) {
\r
340 return respMessage;
\r
348 public <T> Future<T> future(final T t) {
\r
349 return new HFuture<T>(huc) {
\r
350 public boolean evalInfo(HttpURLConnection huc) {
\r
351 if (respCode == 200) {
\r
359 public String body() {
\r
360 if (errContent != null) {
\r
361 return errContent.toString();
\r
362 } else if (respMessage != null) {
\r
363 return respMessage;
\r
365 return Integer.toString(respCode);
\r
371 public Future<Void> future(final HttpServletResponse resp, final int expected) throws APIException {
\r
372 return new HFuture<Void>(huc) {
\r
373 public boolean evalInfo(HttpURLConnection huc) throws IOException, APIException {
\r
374 resp.setStatus(respCode);
\r
377 OutputStream os = resp.getOutputStream();
\r
378 if(respCode==expected) {
\r
379 is = huc.getInputStream();
\r
381 Pooled<byte[]> pbuff = Rcli.buffPool.get();
\r
383 while((read=is.read(pbuff.content))>=0) {
\r
384 os.write(pbuff.content,0,read);
\r
391 is = huc.getErrorStream();
\r
393 is = huc.getInputStream();
\r
396 errContent = new StringBuilder();
\r
397 Pooled<byte[]> pbuff = Rcli.buffPool.get();
\r
399 while((read=is.read(pbuff.content))>=0) {
\r
400 os.write(pbuff.content,0,read);
\r
411 public String body() {
\r
412 return errContent==null?respMessage:errContent.toString();
\r
417 private static class Header {
\r
418 public final String tag;
\r
419 public final String value;
\r
421 public Header(String t, String v) {
\r
426 public String toString() {
\r
427 return tag + '=' + value;
\r
431 public String toString() {
\r
432 return "HttpURLConnection Client configured to " + uri.toString();
\r