/** * */ package com.yunpian.sdk; import java.io.File; import java.io.InputStream; import java.nio.charset.Charset; import java.nio.charset.CodingErrorAction; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.concurrent.Future; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.config.ConnectionConfig; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.HttpAsyncClients; import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager; import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; import org.apache.http.impl.nio.reactor.IOReactorConfig; import org.apache.http.nio.client.HttpAsyncClient; import org.apache.http.nio.reactor.ConnectingIOReactor; import org.apache.http.nio.reactor.IOReactorException; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.yunpian.sdk.api.ApiFactory; import com.yunpian.sdk.api.CallApi; import com.yunpian.sdk.api.FlowApi; import com.yunpian.sdk.api.ShortUrlApi; import com.yunpian.sdk.api.SignApi; import com.yunpian.sdk.api.SmsApi; import com.yunpian.sdk.api.TplApi; import com.yunpian.sdk.api.UserApi; import com.yunpian.sdk.api.VideoSmsApi; import com.yunpian.sdk.api.VoiceApi; import com.yunpian.sdk.constant.YunpianConstant; /** * 开始使用: * * <pre> * YunpianClient yp = new YunpianClient("apikey").init(); * yp.sms().* * yp.sign().* * yp.tpl().* * yp.sms().* * yp.voice().* * yp.flow().* * yp.call().* * yp.close(); * </pre> * * @author dzh * @date Nov 17, 2016 5:17:47 PM * @since 1.2.0 */ public class YunpianClient implements YunpianConstant { static final Logger LOG = LoggerFactory.getLogger(YunpianClient.class); private CloseableHttpAsyncClient clnt; private YunpianConf conf = new YunpianConf(); private ApiFactory api; /** * 构造器里的key作为默认值,方法请求时可以自定义 */ public YunpianClient() { this(System.getProperty(YunpianConf.YP_APIKEY), System.getProperty(YunpianConf.YP_FILE)); } public YunpianClient(String apikey) { this(apikey, System.getProperty(YunpianConf.YP_FILE)); } public YunpianClient(String apikey, String file) { conf.with(apikey); if (file != null) conf.with(new File(System.getProperty(YunpianConf.YP_FILE, file))); } public YunpianClient(String apikey, InputStream in) { conf.with(apikey).with(in); } public YunpianClient(String apikey, Properties props) { conf.with(apikey).with(props); } public UserApi user() { return api.<UserApi> api(UserApi.NAME); } public CallApi call() { return api.<CallApi> api(CallApi.NAME); } public FlowApi flow() { return api.<FlowApi> api(FlowApi.NAME); } public SignApi sign() { return api.<SignApi> api(SignApi.NAME); } public SmsApi sms() { return api.<SmsApi> api(SmsApi.NAME); } public TplApi tpl() { return api.<TplApi> api(TplApi.NAME); } public VoiceApi voice() { return api.<VoiceApi> api(VoiceApi.NAME); } public ShortUrlApi shortUrl() { return api.<ShortUrlApi> api(ShortUrlApi.NAME); } public VideoSmsApi vsms() { return api.<VideoSmsApi> api(VideoSmsApi.NAME); } private static ContentType DefaultContentType; @PostConstruct public YunpianClient init() { LOG.info("YunpianClient is initing!"); try { if (clnt != null) close(); clnt = createHttpAsyncClient(conf.build()); DefaultContentType = ContentType.create("application/x-www-form-urlencoded", Charset.forName(conf.getConf(YunpianConf.HTTP_CHARSET, "utf-8"))); api = new ApiFactory(this); } catch (Exception e) { LOG.error(e.getMessage(), e.fillInStackTrace()); } return this; } public YunpianConf getConf() { return conf; } private CloseableHttpAsyncClient createHttpAsyncClient(YunpianConf conf) throws IOReactorException { IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setIoThreadCount(Runtime.getRuntime().availableProcessors()) .setConnectTimeout(conf.getConfInt(YunpianConf.HTTP_CONN_TIMEOUT, "10000")) .setSoTimeout(conf.getConfInt(YunpianConf.HTTP_SO_TIMEOUT, "30000")).build(); ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(ioReactorConfig); PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(ioReactor); ConnectionConfig connectionConfig = ConnectionConfig.custom().setMalformedInputAction(CodingErrorAction.IGNORE) .setUnmappableInputAction(CodingErrorAction.IGNORE) .setCharset(Charset.forName(conf.getConf(YunpianConf.HTTP_CHARSET, YunpianConf.HTTP_CHARSET_DEFAULT))).build(); connManager.setDefaultConnectionConfig(connectionConfig); connManager.setMaxTotal(conf.getConfInt(YunpianConf.HTTP_CONN_MAXTOTAL, "100")); connManager.setDefaultMaxPerRoute(conf.getConfInt(YunpianConf.HTTP_CONN_MAXPERROUTE, "10")); CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom().setConnectionManager(connManager).build(); httpclient.start(); return httpclient; } static Map<String, String> HEADERS = new HashMap<>(1, 1); static { HEADERS.put("Api-Lang", "java"); } public final Map<String, String> newParam(int size) { return size <= 0 ? Collections.<String, String> emptyMap() : new HashMap<String, String>(size + 1, 1); } /** * * @param uri * @param data */ public Future<HttpResponse> post(String uri, String data) { return post(uri, data, null); } /** * * @param uri * @param data * @since 1.2.6 */ public Future<HttpResponse> post(String uri, String data, String charset) { Charset ch = null; if (charset != null) { ch = Charset.forName(charset); } return post(uri, data, DefaultContentType.getMimeType(), ch, HEADERS); } public void closeResponse(HttpResponse rsp) { EntityUtils.consumeQuietly(rsp.getEntity()); } public Future<HttpResponse> post(String uri, String data, String mimeType, Charset charset, Map<String, String> headers) { return post(uri, new StringEntity(data, ContentType.create(mimeType == null ? DefaultContentType.getMimeType() : mimeType, charset == null ? DefaultContentType.getCharset() : charset)), headers); } public Future<HttpResponse> post(String uri, HttpEntity entity, Map<String, String> headers) { HttpPost req = new HttpPost(uri); req.setEntity(entity); if (headers == null) headers = HEADERS; for (Entry<String, String> e : headers.entrySet()) { req.setHeader(e.getKey(), e.getValue()); } return clnt.execute(req, null); } public HttpAsyncClient http() { return clnt; } @PreDestroy public void close() { LOG.info("YunpianClient is closing!"); if (clnt != null) { try { clnt.close(); } catch (Exception e) { LOG.error(e.getMessage(), e); } } } @Override public String toString() { return conf.toString(); } }