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 com.att.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 com.att.cadi.CadiException;
\r
38 import com.att.cadi.LocatorException;
\r
39 import com.att.cadi.SecuritySetter;
\r
40 import com.att.cadi.client.EClient;
\r
41 import com.att.cadi.client.Future;
\r
42 import com.att.cadi.client.Rcli;
\r
43 import com.att.inno.env.APIException;
\r
44 import com.att.inno.env.Data;
\r
45 import com.att.inno.env.Data.TYPE;
\r
46 import com.att.inno.env.util.Pool.Pooled;
\r
47 import com.att.rosetta.env.RosettaDF;
\r
50 * Low Level Http Client Mechanism. Chances are, you want the high level "HRcli"
\r
51 * for Rosetta Object Translation
\r
55 public class HClient implements EClient<HttpURLConnection> {
\r
57 private ArrayList<Header> headers;
\r
58 private String meth;
\r
59 private String pathinfo;
\r
60 private String query;
\r
61 private String fragment;
\r
62 private Transfer transfer;
\r
63 private SecuritySetter<HttpURLConnection> ss;
\r
64 private HttpURLConnection huc;
\r
65 private int connectTimeout;
\r
67 public HClient(SecuritySetter<HttpURLConnection> ss, URI uri,int connectTimeout) throws LocatorException {
\r
69 throw new LocatorException("No Service available to call");
\r
73 this.connectTimeout = connectTimeout;
\r
74 pathinfo = query = fragment = "";
\r
78 public void setMethod(String meth) {
\r
83 public void setPathInfo(String pathinfo) {
\r
84 this.pathinfo = pathinfo;
\r
88 public void setPayload(Transfer transfer) {
\r
89 this.transfer = transfer;
\r
93 public void addHeader(String tag, String value) {
\r
94 if (headers == null)
\r
95 headers = new ArrayList<Header>();
\r
96 headers.add(new Header(tag, value));
\r
100 public void setQueryParams(String q) {
\r
105 public void setFragment(String f) {
\r
110 public void send() throws APIException {
\r
112 // Build URL from given URI plus current Settings
\r
113 if(uri.getPath()==null) {
\r
114 throw new APIException("Invalid URL entered for HClient");
\r
116 StringBuilder pi = new StringBuilder(uri.getPath());
\r
117 if(!pathinfo.startsWith("/")) {
\r
120 pi.append(pathinfo);
\r
132 huc = (HttpURLConnection) url.openConnection();
\r
134 ss.setSecurity(huc);
\r
136 huc.setRequestMethod(meth);
\r
137 if (headers != null)
\r
138 for (Header d : headers) {
\r
139 huc.addRequestProperty(d.tag, d.value);
\r
141 huc.setDoInput(true);
\r
142 huc.setDoOutput(true);
\r
143 huc.setUseCaches(false);
\r
144 huc.setConnectTimeout(connectTimeout);
\r
146 if (transfer != null) {
\r
147 transfer.transfer(huc.getOutputStream());
\r
149 // TODO other settings? There's a bunch here.
\r
150 } catch (Exception e) {
\r
151 throw new APIException(e);
\r
152 } finally { // ensure all these are reset after sends
\r
153 meth=pathinfo=null;
\r
154 if(headers!=null) {
\r
157 pathinfo = query = fragment = "";
\r
161 public abstract class HFuture<T> extends Future<T> {
\r
162 protected HttpURLConnection huc;
\r
163 protected int respCode;
\r
164 protected String respMessage;
\r
165 protected IOException exception;
\r
166 protected StringBuilder errContent;
\r
168 public HFuture(final HttpURLConnection huc) {
\r
172 protected boolean evalInfo(HttpURLConnection huc) throws APIException, IOException{
\r
173 return respCode == 200;
\r
177 public final boolean get(int timeout) throws CadiException {
\r
179 huc.setReadTimeout(timeout);
\r
180 respCode = huc.getResponseCode();
\r
181 ss.setLastResponse(respCode);
\r
182 if(evalInfo(huc)) {
\r
188 } catch (IOException | APIException e) {
\r
189 throw new CadiException(e);
\r
195 private void extractError() {
\r
196 InputStream is = huc.getErrorStream();
\r
199 is = huc.getInputStream();
\r
202 errContent = new StringBuilder();
\r
204 while((c=is.read())>=0) {
\r
205 errContent.append((char)c);
\r
208 } catch (IOException e) {
\r
213 // Typically only used by Read
\r
214 public StringBuilder inputStreamToString(InputStream is) {
\r
215 // Avoids Carriage returns, and is reasonably efficient, given
\r
216 // the buffer reads.
\r
218 StringBuilder sb = new StringBuilder();
\r
219 Reader rdr = new InputStreamReader(is);
\r
221 char[] buf = new char[256];
\r
223 while ((read = rdr.read(buf)) >= 0) {
\r
224 sb.append(buf, 0, read);
\r
230 } catch (IOException e) {
\r
238 public int code() {
\r
242 public HttpURLConnection huc() {
\r
246 public IOException exception() {
\r
250 public String respMessage() {
\r
251 return respMessage;
\r
255 public String header(String tag) {
\r
256 return huc.getHeaderField(tag);
\r
259 public void close() {
\r
267 public <T> Future<T> futureCreate(Class<T> t) {
\r
268 return new HFuture<T>(huc) {
\r
269 public boolean evalInfo(HttpURLConnection huc) {
\r
270 return respCode==201;
\r
274 public String body() {
\r
275 if (errContent != null) {
\r
276 return errContent.toString();
\r
278 } else if (respMessage != null) {
\r
279 return respMessage;
\r
287 public Future<String> futureReadString() {
\r
288 return new HFuture<String>(huc) {
\r
289 public boolean evalInfo(HttpURLConnection huc) throws IOException {
\r
290 if (respCode == 200) {
\r
291 StringBuilder sb = inputStreamToString(huc.getInputStream());
\r
293 value = sb.toString();
\r
301 public String body() {
\r
302 if (value != null) {
\r
304 } else if (errContent != null) {
\r
305 return errContent.toString();
\r
306 } else if (respMessage != null) {
\r
307 return respMessage;
\r
316 public <T> Future<T> futureRead(final RosettaDF<T> df, final TYPE type) {
\r
317 return new HFuture<T>(huc) {
\r
318 private Data<T> data;
\r
320 public boolean evalInfo(HttpURLConnection huc) throws APIException, IOException {
\r
321 if (respCode == 200) {
\r
322 data = df.newData().in(type).load(huc.getInputStream());
\r
323 value = data.asObject();
\r
330 public String body() {
\r
331 if (data != null) {
\r
333 return data.asString();
\r
334 } catch (APIException e) {
\r
336 } else if (errContent != null) {
\r
337 return errContent.toString();
\r
338 } else if (respMessage != null) {
\r
339 return respMessage;
\r
347 public <T> Future<T> future(final T t) {
\r
348 return new HFuture<T>(huc) {
\r
349 public boolean evalInfo(HttpURLConnection huc) {
\r
350 if (respCode == 200) {
\r
358 public String body() {
\r
359 if (errContent != null) {
\r
360 return errContent.toString();
\r
361 } else if (respMessage != null) {
\r
362 return respMessage;
\r
364 return Integer.toString(respCode);
\r
370 public Future<Void> future(final HttpServletResponse resp, final int expected) throws APIException {
\r
371 return new HFuture<Void>(huc) {
\r
372 public boolean evalInfo(HttpURLConnection huc) throws IOException, APIException {
\r
373 resp.setStatus(respCode);
\r
376 OutputStream os = resp.getOutputStream();
\r
377 if(respCode==expected) {
\r
378 is = huc.getInputStream();
\r
380 Pooled<byte[]> pbuff = Rcli.buffPool.get();
\r
382 while((read=is.read(pbuff.content))>=0) {
\r
383 os.write(pbuff.content,0,read);
\r
390 is = huc.getErrorStream();
\r
392 is = huc.getInputStream();
\r
395 errContent = new StringBuilder();
\r
396 Pooled<byte[]> pbuff = Rcli.buffPool.get();
\r
398 while((read=is.read(pbuff.content))>=0) {
\r
399 os.write(pbuff.content,0,read);
\r
410 public String body() {
\r
411 return errContent==null?respMessage:errContent.toString();
\r
416 private static class Header {
\r
417 public final String tag;
\r
418 public final String value;
\r
420 public Header(String t, String v) {
\r
425 public String toString() {
\r
426 return tag + '=' + value;
\r
430 public String toString() {
\r
431 return "HttpURLConnection Client configured to " + uri.toString();
\r