4f58778094e453e9045363bd82157cff2a151e86
[vfc/nfvo/wfengine.git] / CommonLibrary / rest-client / src / main / java / org / openo / baseservice / roa / util / restclient / HttpBaseRest.java
1 /*
2  * Copyright (c) 2016, Huawei Technologies Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.openo.baseservice.roa.util.restclient;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.IOException;
21 import java.io.UnsupportedEncodingException;
22 import java.net.URLEncoder;
23 import java.text.SimpleDateFormat;
24 import java.util.Calendar;
25 import java.util.Date;
26 import java.util.Map;
27 import java.util.concurrent.atomic.AtomicInteger;
28
29 import org.eclipse.jetty.client.Address;
30 import org.eclipse.jetty.client.HttpClient;
31 import org.eclipse.jetty.client.HttpExchange;
32 import org.eclipse.jetty.http.HttpMethods;
33 import org.openo.baseservice.remoteservice.exception.ServiceException;
34 import org.openo.baseservice.roa.util.ServiceUtil;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 /**
39  * <br/>
40  * <p>
41  * </p>
42  * 
43  * @author
44  * @version SDNO 0.5 Aug 9, 2016
45  */
46 public abstract class HttpBaseRest implements Restful {
47
48     private static final Logger LOG = LoggerFactory.getLogger(HttpRest.class);
49
50     final AtomicInteger requestId = new AtomicInteger(0);
51
52     protected HttpClient client = null;
53
54     private static final String LOCAL_HOST = "127.0.0.1";
55
56     static final String HTTP_PATCH = "PATCH";
57
58     String defaultIP = LOCAL_HOST;
59
60     int defaultPort = -10000;
61
62     int defaultTimeout = 30000;
63
64     final String procenameRouteID = "RouteID-" + System.currentTimeMillis() + "-";
65
66     /**
67      * Constructor<br/>
68      * <p>
69      * </p>
70      * 
71      * @since SDNO 0.5
72      */
73     public HttpBaseRest() {
74         super();
75     }
76
77     protected void createHttpClient() {
78         client = new HttpClient();
79     }
80
81     protected RestHttpContentExchange createRestHttpContentExchange(final RestfulAsyncCallback callback) {
82         final RestHttpContentExchange exchange = new RestHttpContentExchange(true, callback);
83         exchange.setScheme("http");
84         return exchange;
85     }
86
87     private String encodeParams(final RestfulParametes restParametes) throws ServiceException {
88         final Map<String, String> parm = restParametes.getParamMap();
89         String value = null;
90         boolean bHasParma = false;
91         final StringBuilder builder = new StringBuilder();
92         try {
93             for(final String key : parm.keySet()) {
94                 value = parm.get(key);
95                 if(value == null) {
96                     value = "";
97                 }
98                 String str;
99                 if(bHasParma) {
100                     str = String.format("&%s=%s", URLEncoder.encode(key, RestfulClientConst.ENCODING),
101                             URLEncoder.encode(value, RestfulClientConst.ENCODING));
102                 } else {
103                     bHasParma = true;
104                     str = String.format("%s=%s", URLEncoder.encode(key, RestfulClientConst.ENCODING),
105                             URLEncoder.encode(value, RestfulClientConst.ENCODING));
106                 }
107                 builder.append(str);
108             }
109         } catch(final UnsupportedEncodingException ex) {
110             LOG.error("unsupported encoding: ", ex);
111             throw new ServiceException("Broken VM does not support UTF-8");
112         }
113         return builder.toString();
114     }
115
116     private void processHeader(final RestHttpContentExchange contentExchange, final Map<String, String> headerMap) {
117         for(final String key : headerMap.keySet()) {
118             final String value = headerMap.get(key);
119             contentExchange.addRequestHeader(key, value);
120         }
121
122     }
123
124     private void setContentExchangeParams(final RestHttpContentExchange contentExchange) {
125         final String contentType = contentExchange.getRequestFields().getStringField("Content-Type");
126         if(null == contentType || contentType.isEmpty()) {
127             // application/json;charset=utf-8
128             contentExchange.setRequestContentType(RestfulClientConst.APPLICATION_FORM_URLENCODED);
129         }
130         final String encoding = contentExchange.getRequestFields().getStringField("Accept-Encoding");
131         if(null == encoding || encoding.isEmpty()) {
132             // compress,gzip
133             contentExchange.setRequestHeader("Accept-Encoding", "*/*");
134         }
135         contentExchange.setVersion(11);
136     }
137
138     /**
139      * <br/>
140      * 
141      * @param method
142      * @param servicePath
143      * @param restParametes
144      * @param options
145      * @param callback
146      * @return
147      * @throws ServiceException
148      * @since SDNO 0.5
149      */
150     protected RestfulResponse sendHttpRequest(final String method, final String servicePath,
151             final RestfulParametes restParametes, final RestfulOptions options, final RestfulAsyncCallback callback)
152             throws ServiceException {
153         final RestHttpContentExchange contentExchange = createRestHttpContentExchange(callback);
154         if(null == restParametes) {
155             return new RestfulResponse();
156         }
157         final String requestTrace = this.getReuqestIdString();
158         restParametes.putHttpContextHeader(RestfulClientConst.REQUEST_ID, requestTrace);
159
160         RestfulResponse rsp = null;
161         try {
162             contentExchange.setMethod(method);
163             final String str = encodeParams(restParametes);
164             final StringBuilder builder = new StringBuilder();
165             builder.append(servicePath);
166             if(str.length() > 0 && (method.equals(HttpMethods.GET) || method.equals(HttpMethods.DELETE)
167                     || method.equals(HttpMethods.HEAD))) {
168                 builder.append('?');
169                 builder.append(str);
170             }
171             setDefaultUrl(contentExchange, options, builder);
172             processHeader(contentExchange, restParametes.getHeaderMap());
173             setContentExchangeParams(contentExchange);
174
175             setPostPutParam(method, restParametes, contentExchange, str);
176             setTimeout(options, contentExchange);
177
178             client.send(contentExchange);
179             rsp = callbackExecute(callback, contentExchange);
180         } catch(final Exception e) {
181             LOG.error("request reply message have exception:status is "
182                     + RestHttpContentExchange.toState(contentExchange.getStatus()));
183             throw new ServiceException(e);
184         }
185         return rsp;
186     }
187
188     private void setDefaultUrl(final RestHttpContentExchange contentExchange, final RestfulOptions options,
189             final StringBuilder url) {
190         // server
191         if(url.toString().startsWith("http")) {
192             contentExchange.setURL(url.toString());
193         } else {
194             String host = defaultIP;
195             int iPort = defaultPort;
196             String calledServiceName = null;
197             if(options != null) {
198                 calledServiceName = options.getCalledServicName();
199             }
200             final ServiceUtil serviceUtil = new ServiceUtil(calledServiceName, url.toString());
201             final String configHost = serviceUtil.getServiceHost();
202             final int configPort = serviceUtil.getServicePort();
203             if(!configHost.isEmpty() && configPort > 0) {
204                 if(options != null) {
205                     options.setHost(configHost);
206                     options.setPort(configPort);
207                 } else {
208                     host = configHost;
209
210                     iPort = configPort;
211                 }
212             }
213             if(options != null) {
214                 host = options.getHost();
215                 if(host.isEmpty()) {
216                     host = defaultIP;
217                 }
218                 iPort = options.getPort();
219                 if(iPort == 0) {
220                     iPort = defaultPort;
221                 }
222             }
223             // Integer.getInteger(".http.client.maxThread",30)
224             contentExchange.setAddress(new Address(host, iPort));
225             contentExchange.setRequestURI(url.toString());
226         }
227     }
228
229     private String getReuqestIdString() {
230         if(this.requestId.get() == 0x7FFFFFFF) {
231             this.requestId.set(1);
232         }
233         final int reqId = this.requestId.getAndIncrement();
234         final StringBuilder builder = new StringBuilder(this.procenameRouteID);
235         // time
236         final SimpleDateFormat dateFormate = new SimpleDateFormat("yyMMdd");
237         final SimpleDateFormat timeFormate = new SimpleDateFormat("HHmmss");
238         final Date date = Calendar.getInstance().getTime();
239         builder.append(dateFormate.format(date) + timeFormate.format(date));
240         builder.append('-');
241         builder.append(reqId);
242         return builder.toString();
243     }
244
245     private void setPostPutParam(final String method, final RestfulParametes restParametes,
246             final RestHttpContentExchange contentExchange, final String str) throws UnsupportedEncodingException {
247         if(HttpMethods.POST.equals(method) || HttpMethods.PUT.equals(method) || HTTP_PATCH.equals(method)) {
248             ByteArrayInputStream buff;
249             final String tmpRaw = restParametes.getRawData();
250             if(tmpRaw == null) {
251                 buff = new ByteArrayInputStream(str.getBytes(RestfulClientConst.ENCODING));
252             } else {
253                 buff = new ByteArrayInputStream(tmpRaw.getBytes(RestfulClientConst.ENCODING));
254             }
255             final int len = buff.available();
256             contentExchange.setRequestContentSource(buff);
257             contentExchange.setRequestHeader("content-length", String.valueOf(len));
258         }
259     }
260
261     private void setTimeout(final RestfulOptions options, final RestHttpContentExchange contentExchange) {
262         if(options != null) {
263             final long timeout = options.getRestTimeout();
264             if(timeout != 0) {
265                 contentExchange.setTimeout(timeout);
266             } else {
267                 contentExchange.setTimeout(defaultTimeout);
268             }
269         } else {
270             contentExchange.setTimeout(defaultTimeout);
271         }
272     }
273
274     private RestfulResponse callbackExecute(final RestfulAsyncCallback callback,
275             final RestHttpContentExchange contentExchange) throws InterruptedException, IOException, ServiceException {
276         if(callback == null) {
277             final int exchangeState = contentExchange.waitForDone();
278             if(exchangeState == HttpExchange.STATUS_COMPLETED) {
279                 return contentExchange.getResponse();
280             } else if(exchangeState == HttpExchange.STATUS_EXCEPTED) {
281                 throw new ServiceException(
282                         "request is exception: " + RestHttpContentExchange.toState(HttpExchange.STATUS_EXCEPTED));
283             } else if(exchangeState == HttpExchange.STATUS_EXPIRED) {
284                 throw new ServiceException(
285                         "request is expierd: " + RestHttpContentExchange.toState(HttpExchange.STATUS_EXPIRED));
286             }
287         }
288         return null;
289     }
290
291 }