您的位置:首页 > 编程语言 > Java开发

IOT command (based on sip)client API设计 for java

2015-08-18 21:40 661 查看
我们实现的物联网设备控制是通过扩展sip协议来实现的。
由于是基于pjsip来实现的,而pjsip是使用C编程,如何使得业务层(android端,使用java)更容易使用提供的command API
是重点,原始的方法就是从底层C开始往上层层封装(c--->jni--->java),这样存在明显的缺陷:
1. 对于第三方开发开发难度大,工作量多,API设计不合理;
2. 不同的设备控制业务接入代码都需要集成到主程序iot_sip_cli,高耦合,这是不能接受的(特别对于第三方开发)。

所以倒过来考虑,利用IOC原则(don't call us, we'll call you),让第三方开发直接在java层来实现,提供接口给第三方让其将实现注册到iot_sip_cli_jni层,最后jni层的调用被iot_sip_cli驱动。

举例: 接入一个叫test_plugin的设备类型, 它有两个方法test1, test5.

1. 第三方开发首先定义方法的响应处理:
public class TestPluginCallBack {
//以下两个方法最终被iot_sip_cli调用

@CmdCBAnnotation(dev_type = "test_plugin", method_name = "test1")
public void setId(int ret, String retJson) {
}

@CmdCBAnnotation(dev_type = "test_plugin", method_name = "test5")
public void setId2(int ret, String retJson) {
}


};

2.第三方开发将上面的对象,方法传递给 sdk(由sdk内部的IOTCmdAttachment负责):


IOTCmdAttachment att = IOTCmdAttachment.getSingleton();
TestPluginCallBack cbObj = new TestPluginCallBack();
att.registerCmdHandlers(cbObj);


3. 第三方开发,写设备控制的请求发送:
att.inputCommand("test_plugin", "test1", reqJson, toUri); //响应结果retJson通过第一步的方法传到业务层。

这样,第三方开发只要通过上面3个步骤,就能完成对接入设备控制的实现。

过程原理如下图所示(提供给第三方的sdk由CMD_API_4JAVA jar包,和IOT_CMD_JNI so构成):





主要步骤在于IOTCmdAttachment方法registerCmdHandlers的使用:
利用自定义的java注解CmdCBAnnotation, 识别出需要调用的函数,将其传给 jni_reg_cmdcb(它内部调用reg_handler),

public int registerCmdHandlers(Object obj) {
int status = 0;
for (Method m : obj.getClass().getMethods()) {
CmdCBAnnotation a = m.getAnnotation(CmdCBAnnotation.class);
if (a != null) {
Log.d(LOG_TAG, "" + a.dev_type() + ":" + a.method_name());
status =  jni_reg_cmdcb(a.dev_type(), a.method_name(), obj, m);
if (0 != status)
return status;
}
}

return status;
}


static int reg_handler(jstring dev_type,  jstring method_name,  jobject jobj,
jobject jmeth)
{
__android_log_print(ANDROID_LOG_INFO, TAGSTR, "reg_handler");

JNIEnv *env = get_jni_env();
std::string str_devtype = jstring2str(env, dev_type);
std::string str_methname = jstring2str(env, method_name);

//生成DeviceCmdHandler对象,存储设备类型名,设备方法名(即上面注解@CmdCBAnnotation dev_type, method_name值),
//TestPluginCallBack对象,和被注解的java方法
DeviceCmdHandler * pt_dchdl = new DeviceCmdHandler(str_devtype,
str_methname, jobj, jmeth);

//DeviceCmdHandler::methodCallBack4c会使用pt_dchdl作为参数,并且它作为回调函数将被iot_sip_cli调用
int ret = cmd_cb_reg4cpp(str_devtype.c_str(), str_methname.c_str(),
&DeviceCmdHandler::methodCallBack4c, pt_dchdl);
if (0 != ret)
{
__android_log_print(ANDROID_LOG_ERROR, TAGSTR, "reg_handler fail ret %d:%s %s", ret, str_devtype.c_str(),
str_methname.c_str());
}
else
{
__android_log_print(ANDROID_LOG_INFO, TAGSTR, "reg_handler succ:%s %s", str_devtype.c_str(), str_methname.c_str());
}
return ret;
}


  

DeviceCmdHandler类如下:





int DeviceCmdHandler::methodCallBack4c(int ret_i, const char * ret_json,
void * pt_obj) {
return ((DeviceCmdHandler *) pt_obj)->methodCallBack(ret_i, ret_json);
}
而 DeviceCmdHandler::methodCallBack(int ret_i, const char * ret_json)方法,最终调用
CallObjectMethod(env, this->mJmethod, mid, jo, (jobjectArray) texts); 即调用java层的TestPluginCallBack两个注解的方法。

mid获取, 使用java.lang.reflect.Method:
JLocalRef<jclass> clazz = env->GetObjectClass(this->mJmethod);
jmethodID mid = env->GetMethodID(clazz, "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: