Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package com.cloudfoundry.bae.cloudpush; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NavigableSet; import java.util.Set; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.json.JSONException; import org.json.JSONObject; /** * Channel * * <p>Channel?????JavaSDKaccess_token * ?????</p> * * @author zhuanght(zhuang.hai.tao@163.com) * @version 0.0.1 */ public class Channel extends BaeBase { private static final Log logger = LogFactory.getLog(Channel.class); /* * ??KEY * * * ChannelSDK??????????$optional * $optional?KEY */ /** * ? */ public static final String TIMESTAMP = "timestamp"; /** * * ?10 */ public static final String EXPIRES = "expires"; /** * API? * ?? */ public static final String VERSION = "v"; /** * ??ID? */ public static final String CHANNEL_ID = "channel_id"; /** * ID * 01 */ public static final String USER_TYPE = "user_type"; /** * ID * * 01 * */ public static final String DEVICE_TYPE = "device_type"; /** * * * ??start0 * */ public static final String START = "start"; /** * ?? * * ??limit100? * */ public static final String LIMIT = "limit"; /** * ?ID json * */ public static final String MSG_IDS = "sg_ids"; public static final String MSG_KEYS = "msg_keys"; public static final String IOS_MESSAGES = "ios_messages"; public static final String WP_MESSAGES = "wp_messages"; /** * ? * * 0 * */ public static final String MESSAGE_TYPE = "message_type"; /** * ? * */ public static final String MESSAGE_EXPIRES = "message_expires"; /** * ??? * */ public static final String TAG_NAME = "tag"; /** * ??? * */ public static final String TAG_INFO = "info"; /** * ?id * */ public static final String TAG_ID = "tid"; /** * ?? * */ public static final String BANNED_TIME = "banned_time"; /** * ?? * */ public static final String CALLBACK_DOMAIN = "domain"; /** * uri * */ public static final String CALLBACK_URI = "uri"; /** * Channel? * * ? */ public static final String APPID = "appid"; public static final String ACCESS_TOKEN = "access_token"; public static final String API_KEY = "apikey"; public static final String SECRET_KEY = "secret_key"; public static final String SIGN = "sign"; public static final String METHOD = "method"; public static final String HOST = "host"; public static final String USER_ID = "user_id"; public static final String MESSAGES = "messages"; public static final String PRODUCT = "channel"; public static final String DEFAULT_HOST = "channel.api.duapp.com"; public static final String NAME = "name"; public static final String DESCRIPTION = "description"; public static final String CERT = "cert"; public static final String RELEASE_CERT = "release_cert"; public static final String DEV_CERT = "dev_cert"; public static final String PUSH_TYPE = "push_type"; /** * Channel??? * * ? */ private String apiKey = null; private String secretKey = null; private int requestId = 0; private int CONN_TIMEOUT = 30; private ConnectionOption connOption = ConnectionOption.DEFAULT; public static final int PUSH_TO_USER = 1; public static final int PUSH_TO_TAG = 2; public static final int PUSH_TO_ALL = 3; public static final int PUSH_TO_DEVICE = 4; /** * Channel ? * * ? */ public static final int CHANNEL_SDK_SYS = 1; public static final int CHANNEL_SDK_INIT_FAIL = 2; public static final int CHANNEL_SDK_PARAM = 3; public static final int CHANNEL_SDK_HTTP_STATUS_ERROR_AND_RESULT_ERROR = 4; public static final int CHANNEL_SDK_HTTP_STATUS_OK_BUT_RESULT_ERROR = 5; /** * ? * * ? */ private String[] arrayErrorMap = { "php sdk error", "php sdk error", "lack param", "http status is error, and the body returned is not a json string", "http status is ok, but the body returned is not a json string" }; /** * * apiKeysecretKey? * @param string apiKey * @param string secretKey * @param array arr_curlOpts ?? * @throws ChannelException ?CHANNEL_SDK_INIT_FAIL */ public void initialize(String apiKey, String secretKey, ConnectionOption option) { if (checkString(apiKey, 1, 64)) { this.apiKey = apiKey; } else { throw new ChannelException( "invalid param - apiKey[" + apiKey + "]," + "which must be a 1 - 64 length string", CHANNEL_SDK_INIT_FAIL); } if (checkString(secretKey, 1, 64)) { this.secretKey = secretKey; } else { throw new ChannelException( "invalid param - secretKey[" + secretKey + "]," + "which must be a 1 - 64 length string", CHANNEL_SDK_INIT_FAIL); } if (option != null) { this.connOption = option; } resetErrorStatus(); } /** * setApiKey * * * ? ChannelapiKeyChannel??apiKey? * * @param string apiKey * @return ?truefalse * * @version */ public boolean setApiKey(String apiKey) { this.resetErrorStatus(); try { if (this.checkString(apiKey, 1, 64)) { this.apiKey = apiKey; } else { throw new ChannelException("invaid apiKey ( " + apiKey + " ), which must be a 1 - 64 length string", CHANNEL_SDK_INIT_FAIL); } } catch (ChannelException ex) { this.channelExceptionHandler(ex); return false; } return true; } /** * setSecretKey * * * ? ChannelsecretKeyChannel??secretKey? * * @access public * @param string $secretKey * @return ?truefalse * * @version */ public boolean setSecretKey(String secretKey) { this.resetErrorStatus(); try { if (this.checkString(secretKey, 1, 64)) { this.secretKey = secretKey; } else { throw new ChannelException( "invaid secretKey ( " + secretKey + " ), which must be a 1 - 64 length string", CHANNEL_SDK_INIT_FAIL); } } catch (ChannelException ex) { this.channelExceptionHandler(ex); return false; } return true; } /** * getRequestId * * * ??request_idSDK0 * * @return ?request_id * * @version 1.0.0.0 */ public int getRequestId() { return this.requestId; } /** * queryBindList * * * * ??userId[?channelId]? * * @access public * @param string userId ID? * @param array optional ?????CHANNEL_ID?DEVICE_TYPE?START?LIMIT * @return ?JSONObjectnull * * @version 1.0.0.0 */ public JSONObject queryBindList(String userId, Map<String, String> optional) { this.resetErrorStatus(); try { Map<String, String> args = new HashMap<String, String>(optional); args.put(USER_ID, userId); String[] needArray = { USER_ID }; args = prepareArgs(needArray, args); args.put(METHOD, "query_bindlist"); return this.commonProcess(args); } catch (ChannelException ex) { this.channelExceptionHandler(ex); return null; } } /** * pushMessage * * ?pushType, messages, message_type, [optinal] ?? * @access public * @param int pushType ? ? 1-4, 1:?2tag 3 4 * @param string messages ??????json_encode;json?msgKeys?; * @param array optional ??,pushType?USER_ID(:optional[USER_ID] = "xxx"), * pushTypetagTAG, * ??MSG_KEYS ???key??json_encodemessages?; * MESSAGE_TYPE ?? 0-1, 0:??10 * ?MESSAGE_EXPIRES, MESSAGE_EXPIRES, CHANNLE_ID * * @return ?JSONObject:null * @version 2.0.0.0 */ public JSONObject pushMessage(int pushType, String messages, String msgKeys, Map<String, String> optional) { this.resetErrorStatus(); try { Map<String, String> args = new HashMap<String, String>(optional); args.put(PUSH_TYPE, String.valueOf(pushType)); args.put(MESSAGES, messages); args.put(MSG_KEYS, msgKeys); String[] needArray = { PUSH_TYPE, MESSAGES, MSG_KEYS }; args = prepareArgs(needArray, args); args.put(METHOD, "push_msg"); switch (pushType) { case PUSH_TO_USER: if (!args.containsKey(USER_ID) || args.get(USER_ID) == null || args.get(USER_ID).isEmpty()) { throw new ChannelException( "userId should be specified in optional when pushType is PUSH_TO_USER", CHANNEL_SDK_PARAM); } break; case PUSH_TO_TAG: if (!args.containsKey(TAG_NAME) || args.get(TAG_NAME) == null || args.get(TAG_NAME).isEmpty()) { throw new ChannelException("tag should be specified in optional[] when pushType is PUSH_TO_TAG", CHANNEL_SDK_PARAM); } break; case PUSH_TO_ALL: break; case PUSH_TO_DEVICE: if (!args.containsKey(CHANNEL_ID)) { throw new ChannelException( "channelId should be specified in optional[] when pushType is PUSH_TO_DEVICE", CHANNEL_SDK_PARAM); } break; default: throw new ChannelException("pushType value is not supported or not specified", CHANNEL_SDK_PARAM); } return this.commonProcess(args); } catch (ChannelException ex) { this.channelExceptionHandler(ex); return null; } } /** * checkString * * ? * * ??min?max * * @param string str ? * @param int min ? * @param int max * @return ?truefalse * * @version 1.0.0.0 */ private boolean checkString(String str, int min, int max) { if (str != null && str.length() >= min && str.length() <= max) { return true; } return false; } /** * * ? * * ? * * @access protected * @param Excetpion $ex ??Channel?? * * @version 1.0.0.0 */ private void channelExceptionHandler(ChannelException ex) { int tmpCode = ex.code; if (0 == tmpCode) { tmpCode = CHANNEL_SDK_SYS; } this.errcode = tmpCode; if (this.errcode >= 30000) { this.errmsg = ex.getMessage(); } else { this.errmsg = arrayErrorMap[this.errcode]; } } /** * resetErrorStatus * * ? * * ?????? * * @version 1.0.0.0 */ private void resetErrorStatus() { this.errcode = 0; this.errmsg = this.arrayErrorMap[errcode]; this.requestId = 0; } /** * commonProcess * * ? * * ?SDK * * @access protected * @param map paramOpt ? * @throws ChannelException * * @version 1.0.0.0 */ private JSONObject commonProcess(Map<String, String> paramOpt) { adjustOpt(paramOpt); ResponseCore ret = baseControl(paramOpt); if (ret == null) { throw new ChannelException("base control returned empty object", CHANNEL_SDK_SYS); } if (ret.isOK()) { try { JSONObject result = new JSONObject(ret.body); this.requestId = result.getInt("request_id"); return result; } catch (JSONException ex) { throw new ChannelException(ret.body, CHANNEL_SDK_HTTP_STATUS_OK_BUT_RESULT_ERROR); } } else { try { JSONObject result = new JSONObject(ret.body); this.requestId = result.getInt("request_id"); throw new ChannelException(result.getString("error_msg"), result.getInt("error_code")); } catch (JSONException ex) { throw new ChannelException("ret body:" + ret.body, CHANNEL_SDK_HTTP_STATUS_ERROR_AND_RESULT_ERROR); } } } /** * prepareArgs * * ? * * ???? * * @access protected * @param array arrNeed ?KEY * @param map tmpArgs ? * @throws ChannelException ?self::Channel_SDK_PARAM * * @version 1.0.0.0 */ public Map<String, String> prepareArgs(String[] arrNeed, Map<String, String> tmpArgs) { Map<String, String> args; if (null == tmpArgs || tmpArgs.isEmpty()) { args = new HashMap<String, String>(); return args; } if (null != arrNeed && arrNeed.length > 0 && tmpArgs.isEmpty()) { String keys = "("; for (String key : arrNeed) { keys += key + ","; } keys += ")"; throw new ChannelException("invalid sdk params, params" + keys + "are needed", CHANNEL_SDK_PARAM); } if (null != arrNeed) { for (String key : arrNeed) { if (!tmpArgs.containsKey(key)) { throw new ChannelException("lack param (" + key + ")", CHANNEL_SDK_PARAM); } } } args = new HashMap<String, String>(tmpArgs); if (args.containsKey(CHANNEL_ID)) { String channelIDValue = (String) args.get(CHANNEL_ID); args.put(CHANNEL_ID, channelIDValue); // URLCodec codec = new URLCodec("utf8"); // String channelIDValue = (String)args.get(CHANNEL_ID); // try { // args.put(CHANNEL_ID, codec.encode(channelIDValue)); // } catch (EncoderException ex) { // throw new ChannelException("bad channel_id (" + channelIDValue + ")", CHANNEL_SDK_PARAM); // } } return args; } /** * adjustOpt * * ? * * ? * * @param Map opt ?map * @throws ChannelException ? CHANNEL_SDK_PARAM * * @version 1.0.0.0 */ private void adjustOpt(Map<String, String> opt) { if (null == opt || opt.isEmpty()) { throw new ChannelException("no params are set", CHANNEL_SDK_PARAM); } if (!opt.containsKey(TIMESTAMP)) { String timestamp = String.valueOf(System.currentTimeMillis() / 1000); opt.put(TIMESTAMP, timestamp); } opt.put(HOST, DEFAULT_HOST); opt.put(API_KEY, apiKey); if (opt.containsKey(SECRET_KEY)) { opt.remove(SECRET_KEY); } } /** * _baseControl * * ? * * * * @param Map opt ? * @throws ChannelException ?CHANNEL_SDK_SYS * * @version 1.0.0.0 */ private ResponseCore baseControl(Map<String, String> opt) { StringBuilder content = new StringBuilder(); String resource = "channel"; if (opt.containsKey(CHANNEL_ID) && opt.get(CHANNEL_ID) != null) { resource = opt.get(CHANNEL_ID); opt.remove(CHANNEL_ID); } String host = opt.get(HOST); opt.remove(HOST); String url = "http://" + host + "/rest/2.0/" + PRODUCT + "/"; url += resource; HttpMethod httpMethod = HttpMethod.HTTP_POST; String sign = genSign(httpMethod.toString(), url, opt); opt.put(SIGN, sign); Set<String> keys = opt.keySet(); for (String key : keys) { try { // try { //// key = new URLCodec("utf8").encode(key); //// String v = new URLCodec("utf8").encode(opt.get(key)); // content.append(key).append("=").append(opt.get(key)).append("&"); // } catch (EncoderException ex) { // Logger.getLogger(Channel.class.getName()).log(Level.SEVERE, null, ex); // } String v = URLEncoder.encode(opt.get(key), "utf8"); content.append(key).append("=").append(v).append("&"); } catch (UnsupportedEncodingException ex) { Logger.getLogger(Channel.class.getName()).log(Level.SEVERE, null, ex); } } String postContent = content.toString(); postContent = postContent.substring(0, postContent.length() - 1); logger.info("content = " + postContent); logger.info("url = " + url); RequestCore request = new RequestCore(url); Map<String, String> headers = new HashMap<String, String>(); headers.put("Content-Type", "application/x-www-form-urlencoded"); headers.put("User-Agent", "Baidu Channel Service Javasdk Client"); Set<String> headerKeySet = headers.keySet(); for (String headerKey : headerKeySet) { String headerValue = headers.get(headerKey); request.addHeader(headerKey, headerValue); } request.setMethod(httpMethod); request.setBody(postContent); request.setConnectionOption(connOption); request.sendRequest(); return new ResponseCore(request.getResponseHeader(), request.getResponseBody(), request.getResponseCode()); } /** * genSign * * ? * * ?method, url, ? ??? */ private String genSign(String method, String url, Map<String, String> opt) { String gather = method + url; TreeMap<String, String> sortOpt = new TreeMap<String, String>(opt); NavigableSet<String> keySet = sortOpt.navigableKeySet(); Iterator<String> it = keySet.iterator(); while (it.hasNext()) { String key = it.next(); String value = sortOpt.get(key); gather += key + "=" + value; } gather += secretKey; logger.info("sign source content: " + gather); String encodedGather; try { // encodedGather = new URLCodec("utf8").encode(gather); encodedGather = URLEncoder.encode(gather, "utf8"); } catch (UnsupportedEncodingException ex) { throw new ChannelException("wrong params are seted: " + gather, CHANNEL_SDK_PARAM); } String sign = DigestUtils.md5Hex(encodedGather); return sign; } }