com.cloudfoundry.bae.cloudpush.Channel.java Source code

Java tutorial

Introduction

Here is the source code for com.cloudfoundry.bae.cloudpush.Channel.java

Source

/*
 * 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;
    }
}