DarkMatter in Cyberspace
  • Home
  • Categories
  • Tags
  • Archives

GAPI的同步返回实现方法


GAPI 所基于 MINA 是一个异步网络通信框架,因此要实现 API 调用的同步方式返回,需要采用锁机制,即在主线程启动 filter 后进入“睡眠”状态, 当filter 处理任务完毕后唤醒主线程继续运行。具体实现的方法如下(以 execScript() 方法为例)。

测试用例:

public class SimpleExpScriptTest {

private IConnection conn;

@Test

public void testPWD() throws Exception {

conn = ConnFactory.getInstance().getConnection(Constants.PORT_CONNECT_GODU_DATA);

conn.setSyncType(Constants.TYPE_DATA_CMD_SYNC);

if (conn.getConnection("<7001>", "goduapp", "10.0.2.47", 1234, 100)) {

System.out.println("Connect GODU OK!");

}

conn.sendGoduCmd("settelnetcodec switch=y");

conn.set_script_timeout(500);

Map params = new HashMap();

params.put("user_name", "test");

params.put("old_pwd", "godu123");

params.put("new_pwd", "testgodu");

IResult result = conn. execScript ("-1200187081", "script/PWD", "", params);

System.out.println("***result is:\n" + result.getString());

}

}

execScript 方法:

package com.boco.godu.gapi.conn;

import ...

public class GoduDataConnection extends AbstractConnection {

private static final GapiLogger logger = LogUtils.getLogger(this.getClass().getName());

private final Object lock = new Object(); //对象锁

public IResult execScript(String ne_id, String scriptPath, String name, Map params) throws ... {

// check if connected GODU successfully

...

// parse script file

GoduScript gs = new GoduScript(scriptPath, script_buffer_size, params);

// add execute_script filter

session.getFilterChain().addBefore(...);

// open NE

...

// 在执行完脚本或者超时之前阻止代码继续运行,在ExecScriptFilter.messageReceived方法中解锁

GapiIosessionUtils. lockSession (session, lock , script_timeout );

GoduReturnResult res = new GoduReturnResult();

String script_result = (String) session.getAttribute(

      ExecScriptFilter.EXEC_SCRIPT_RESULT, "");

res.setArrays(script_result.getBytes());

int return_status = (Integer) session.getAttribute(

      ExecScriptFilter.EXEC_SCRIPT_RETURN_STATUS, 0);

res.setReturnStatus(return_status);

return res;

}

}

这样代码运行到lockSession时暂停,直到超时时间到,或者被其他线程上持有同一个锁的“唤醒”方法唤醒,这实现了同步方式的前一半:下面是同步方式的后一半:filter执行脚本完毕后唤醒主线程继续运行:

package com.boco.godu.gapi.mina.filter.data;

import ...

public class ExecScriptFilter extends AGapiFilter {

@Override

public void messageReceived(NextFilter nextFilter, IoSession session,

     Object message) throws Exception {

...

if (...) { // 如果脚本执行完毕:

...

GapiIosessionUtils. unlockSession (session);

return;

}

...

}

}

那么 lockSession 和 unlockSession 方法又是如何实现的呢,继续往下看:

public class GapiIosessionUtils {

public static void lockSession(final IoSession session, final Object lock , final int timeout ) throws ... {

try {

if (session.isConnected() && !session.isClosing()) {

 long beforeLockTime = System.currentTimeMillis();

 session.setAttribute(GoduFilterConstants. GODU_DATA_LOCK , lock );

 session.getConfig().setBothIdleTime(timeout);

 ThreadUtil. waitIt ( lock , timeout * 1000 + 1000);

 long afterLockTime = System.currentTimeMillis();

 logger.debug("lockTime=" + (afterLockTime - beforeLockTime) + "ms");

}

} catch (Exception e) {

e.printStackTrace();

logger.error("lockSession exception: ", e);

throw new GapiException(e);

}

}

public static void unlockSession(final IoSession session) throws ... {

try {

if (session.isConnected() && !session.isClosing()) {

 Object status = session.getAttribute(GoduFilterConstants. GODU_DATA_LOCK );

 ThreadUtil.notifyIt(status);

}

} catch (Exception e) {

...

}

}

}

可以看到加锁的时候将锁(lock对象)放在了session的一个attribute上,解锁的时候从这个attribute上取出这个锁,然后解锁。这里用到的 冻结线程的 waitIt 方法以及唤醒线程的 notifyIt 方法实现如下:

package com.boco.godu.common.util;

public class ThreadUtil {

public static void waitIt (final Object o, final long time) {

synchronized (o) {

try {

 if (time == -1) {

  o.wait();

 } else {

  o.wait(time);

 }

} catch (InterruptedException iex) {

 iex.printStackTrace();

}

}

}

public static void notifyIt (final Object o) {

synchronized (o) {

 o.notifyAll();

}

}

}

当代码到 o.wait(time); 时进入阻塞状态(停止运行,实际上是java.lang.Object.wait()方法),直到下列情况之一出现:

  1. 超时时间time到;

  2. 被唤醒,也就是调用同一个对象的notifyAll方法(即java.lang.Object.notifyAll()方法)。



Published

Jul 26, 2011

Last Updated

Jul 26, 2011

Category

Tech

Tags

  • GAPI 1
  • 同步锁 1

Contact

  • Powered by Pelican. Theme: Elegant by Talha Mansoor