2005-03-17
■ [java][JavaScript][JSON-RPC-Java][Tapestry] JSONRpcClientを作ってみた。
Tapestryとのコンボをやってみた。もっとうまい方法があるかも知れんけど。
使い方はこんな感じで。
<script jwcid="@brownie:JSONRpcClient" registerObjects="ognl: jsonObjects" />
registerObjectsは、クライアント側からアクセスするサーバー側のオブジェクトと名前のMapオブジェクトを指定します(名前がkeyでオブジェクトがvalueね)。
んで、例えば何かのボタンが押されたときにサーバー側にメッセージを送るとすると、
<script language="JavaScript" > 
function onclick_btnGetXXXXXX( btn ) {
	var key = document.Form0.field_key.value;
	var value = jsonrpc.serverObjeName.getXXXXXX( key );
	document.Form0.field_value.value = value
}
</script>
			この場合、上のJSONRpcClientのregisterObjectsには、getXXXXXメソッドを持つオブジェクトをkeyを"serverObjeName"としてMapにputする必要があります。
で実装の方はどうなっているかってーと、component-specificationはこんな感じ。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE component-specification PUBLIC 
  "-//Apache Software Foundation//Tapestry Specification 3.0//EN" 
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
  
<component-specification class="org.asyrinx.brownie.tapestry.components.jsonrpc.JSONRpcClient" allow-body="no" allow-informal-parameters="no">
  <description>
	JSON-RPC-Java client component  	
  </description>
  <parameter name="servletMappingUrl" type="java.lang.String" direction="in" default-value='"/JSON-RPC"'>
      <description>the mapping URL for JSONRPCServlet</description>
  </parameter>
  
  <parameter name="clientName" type="java.lang.String" direction="in" default-value='"jsonrpc"'>
      <description>variable name of JSONRpcClient object in JavaScript</description>
  </parameter>
  
  <parameter name="registerObjects" type="java.util.Map" direction="in" required="yes"/>
</component-specification>
			登録したオブジェクトをJavaScript側から使うための名前は、Mapで指定するregisterObjectsのkeyが使われます。
package org.asyrinx.brownie.tapestry.components.jsonrpc;
import java.util.Iterator;
import java.util.Map;
import org.apache.tapestry.AbstractComponent;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.asyrinx.brownie.tapestry.script.IScriptUser;
import org.asyrinx.brownie.tapestry.script.ScriptUsage;
import org.asyrinx.brownie.tapestry.script.ScriptWriter;
import org.asyrinx.brownie.tapestry.util.Scope;
import com.metaparadigm.jsonrpc.JSONRPCBridge;
/**
 * @author takeshi
 */
public abstract class JSONRpcClient extends AbstractComponent implements
        IScriptUser {
    private final ScriptWriter scriptWriter;
    public JSONRpcClient() {
        super();
        this.scriptWriter = new ScriptWriter(this, "JSONRpcClient.script");
        this.scriptWriter.setUsage(ScriptUsage.ONCE_BY_OBJECT);
    }
    public void prepareScriptSymbols(Map symbols, IRequestCycle cycle) {
        symbols.put("clientName", getClientName());
        symbols.put("contextPath", cycle.getRequestContext().getRequest()
                .getContextPath());
        symbols.put("servletMappingUrl", getServletMappingUrl());
    }
    protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {
        if (cycle.isRewinding())
            return;
        prepareBridge(cycle);
        scriptWriter.execute(cycle);
    }
    private static final String KEY_BRIDGE_ON_SESSION = "JSONRPCBridge";
    protected JSONRPCBridge prepareBridge(IRequestCycle cycle) {
        //final String key = this.getClass().getName() + "." + getClientName();
        final String key = KEY_BRIDGE_ON_SESSION;
        JSONRPCBridge result = (JSONRPCBridge) getScopeObject().getAttribute(
                cycle, key);
        if (result == null) {
            result = new JSONRPCBridge();
            getScopeObject().setAttribute(cycle, key, result);
        }
        for (Iterator i = getRegisterObjects().entrySet().iterator(); i
                .hasNext();) {
            final Map.Entry entry = (Map.Entry) i.next();
            result.registerObject(entry.getKey(), entry.getValue());
        }
        return result;
    }
    private Scope getScopeObject() {
        return Scope.SESSION;
    }
    public abstract String getServletMappingUrl();
    /**
     * request, session, application
     * 
     * @return
     */
    //public abstract String getScope();
    public abstract Map getRegisterObjects();
    public abstract String getClientName();
}
			JSONRPCBridgeオブジェクトに登録するときには、sessionを使うしかないのね。それで問題はないんだけど、applicationで登録できてもいいなーと思ったり。
<?xml version="1.0"?>
<!-- $Id: DateValidator.script,v 1.3 2003/06/01 05:05:12 hlship Exp $ -->
<!DOCTYPE script PUBLIC
	"-//Apache Software Foundation//Tapestry Script Specification 3.0//EN"
	"http://jakarta.apache.org/tapestry/dtd/Script_3_0.dtd">
	
<script>
	
<include-script resource-path="/org/asyrinx/brownie/tapestry/components/jsonrpc/jsonrpc.js"/>
<input-symbol key="clientName" class="java.lang.String" required="yes"/>
<input-symbol key="contextPath" class="java.lang.String" required="yes"/>
<input-symbol key="servletMappingUrl" class="java.lang.String" required="yes"/>
<body>
var ${clientName} = null;
</body>
<initialization>
${clientName} = new JSONRpcClient("${contextPath}${servletMappingUrl}");
</initialization>
</script>
			JavaScript側で使うJSONRpcClientオブジェクトを生成するだけです。
jsonrpc.jsもコピーしておく必要があります。
[コメントを書く]