未来之路

THE ROAD TO THE FUTURE

翻译 Ready, Set, Go - Getting started with Tuscany收藏

新一篇: Weblogic环境下的JSP预编译图文说明,新鲜出炉,呵呵 | 旧一篇: Linux下apache2+SVN环境下使用问题总结

安装Tuscany的Eclipse插件

※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

英文原文版权归原作者所有, 本译文转载请注明出处!

译者:abigfrog 联系:QQ:800736, MSN:J2EE@HOTMAIL.COM

※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

    首先,启动Eclipse,并依次点击菜单:Help -> Software Updates -> Find and Install,选择“Search for new features to install”,点击下一步:

 

在接下来的对话框中,点击“New Remote Site…”创建一个新的站点,命名为“Tuscany”,其地址为:http://people.apache.org/~jsdelfino/tuscany/tools/updatesite/
确认选择了我们刚刚新增的一个远程站点,并点击“Finish”按钮
   
现在,项目如下:
 
组装服务
现在我们有了所有的服务实现,现在将要把它们组合在以前,以提供商店服务,集成配置保存在一个后缀为.composite的文件中。
src目录新建一个store.composite文件,将下面的内容复制进去:
<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
    xmlns:t
="http://tuscany.apache.org/xmlns/sca/1.0"
    xmlns:s
="http://store"
    name
="store">
    
<!—原文如此,错误
    <component name="store"
>
        
<t:implementation.widget location="ufservices/store.html"/>
        
<service name="Widget">
            
<t:binding.http/>
        
</service>
                
<reference name="catalog" target="Catalog">
             
<t:binding.jsonrpc/>
         
</reference>
         
<reference name="shoppingCart" target="ShoppingCart">
             
<t:binding.atom/>
         
</reference>
    
</component>
    -->
    
<!—正确的应该这样 -->
    
<component name="store">
        
<t:implementation.resource location="ufservices"/>
        
<service name="Resource">
            
<t:binding.http/>
        
</service>
    
</component>
    
<!—正确的应该这样 -->
    
<component name="Catalog">
        
<implementation.java class="services.CatalogImpl"/>
        
<property name="currencyCode">USD</property>
        
<service name="Catalog">
            
<t:binding.jsonrpc/>
        
</service>
        
<reference name="currencyConverter" target="CurrencyConverter"/>
    
</component>
    
<component name="ShoppingCart">
        
<implementation.java class="services.ShoppingCartImpl"/>
        
<service name="Collection">
            
<t:binding.atom/>
        
</service>
    
</component>
    
<component name="CurrencyConverter">
        
<implementation.java class="services.CurrencyConverterImpl"/>
    
</component>
</composite>
 
现在,项目是这个样子的:
 
译者注:根据对发布包中例程的观察,发现,此教程中少了两个关键的js脚本文件:binding-atom.js、binding-jsonrpc.js,分别是提供atom绑定和jsonrpc绑定服务的,这里附上代码:
Binding-atom.js源程序:
function AtomClient(uri) {
    
    
this.uri=uri;
    
    
this.get = function(id, responseFunction) {
        
var xhr = this.createXMLHttpRequest();
        xhr.onreadystatechange 
= function() {
            
if (xhr.readyState == 4) {
                
if (xhr.status == 200) {
                    
if (responseFunction !== null) {
                        responseFunction(xhr.responseXML);
                    }
                } 
else {
                    alert(
"get - Error getting data from the server");
                }
            }
        };
        xhr.open(
"GET", uri + id, true);
        xhr.send(
null);
    };    
    
this.post = function (entry, responseFunction) {
        
var xhr = this.createXMLHttpRequest();
        xhr.onreadystatechange 
= function() {
            
if (xhr.readyState == 4) {
                
if (xhr.status == 201) {
                    
if (responseFunction !== null) {
                        responseFunction(xhr.responseXML);
                    }
                } 
else {
                    alert(
"post - Error getting data from the server");
                }
            }
        };
        xhr.open(
"POST", uri, true);
        xhr.setRequestHeader(
"Content-Type""application/atom+xml");
        xhr.send(entry);
    };
    
this.put = function (id, entry, responseFunction) {
        
var xhr = this.createXMLHttpRequest();
        xhr.onreadystatechange 
= function() {
            
if (xhr.readyState == 4) {
                
if (xhr.status == 200) {
                    
if (responseFunction !== null) {
                        responseFunction(xhr.responseXML);
                    }
                } 
else {
                    alert(
"put - Error getting data from the server");
                }
            }
        };
        xhr.open(
"PUT", uri + id, true);
        xhr.setRequestHeader(
"Content-Type""application/atom+xml");
        xhr.send(entry);
    };
    
this.del = function (id, responseFunction) {       
        
var xhr = this.createXMLHttpRequest();
        xhr.onreadystatechange 
= function() {
            
if (xhr.readyState == 4) {
                
if (xhr.status == 200) {
                    
if (responseFunction !== null) {
                        responseFunction();
                    }
                } 
else {
                    alert(
"delete - Error getting data from the server");
                }
            }
        };
        xhr.open(
"DELETE", uri + id, true);        
        xhr.send(
null);
    };
    
    
this.createXMLHttpRequest = function () {
        
try {return new XMLHttpRequest();} catch(e) {}      
        
try {return new ActiveXObject("Msxml2.XMLHTTP");} catch(e) {}
        
try {return new ActiveXObject("Microsoft.XMLHTTP");} catch(e) {}
        alert(
"XML http request not supported");
        
return null;
    };
}

bindingatom 
= "loaded";
 
译者注:此js脚本经过译者修正,原脚本文件在eclipse中会报一些语法错误。
 
binding-jsonrpc.js源程序:
escapeJSONChar =
function escapeJSONChar(c)
{
    
if(c == """ || c == "\"return "\" + c;
    
else if (c == ""return "\b";
    
else if (c == " "return "\f";
    
else if (c == " "return "\n";
    
else if (c == " "return "\r";
    
else if (c == " "return "\t";
    
var hex = c.charCodeAt(0).toString(16);
    
if(hex.length == 1return "\u000" + hex;
    
else if(hex.length == 2return "\u00" + hex;
    
else if(hex.length == 3return "\u0" + hex;
    
else return "\u" + hex;
};


/* encode a string into JSON format */

escapeJSONString 
=
function escapeJSONString(s)
{
    
/* The following should suffice but Safari's regex is b0rken
       (doesn't support callback substitutions)
       return """ + s.replace(/([^ -]|[\"])/g,
       escapeJSONChar) + """;
    
*/

    
/* Rather inefficient way to do it */
    
var parts = s.split("");
    
for(var i=0; i < parts.length; i++) {
    
var c =parts[i];
    
if(c == '"' ||
       c 
== '\' ||
       c.charCodeAt(
0< 32 ||
       c.charCodeAt(
0>= 128)
        parts[i] 
= escapeJSONChar(parts[i]);
    }
    
return """ + parts.join(""+ """;
};


/* Marshall objects to JSON format */

toJSON 
= function toJSON(o)
{
    
if(o == null) {
    
return "null";
    } 
else if(o.constructor == String) {
    
return escapeJSONString(o);
    } 
else if(o.constructor == Number) {
    
return o.toString();
    } 
else if(o.constructor == Boolean) {
    
return o.toString();
    } 
else if(o.constructor == Date) {
    
return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}';
    } 
else if(o.constructor == Array) {
    
var v = [];
    
for(var i = 0; i < o.length; i++) v.push(toJSON(o[i]));
    
return "[" + v.join(""+ "]";
    } 
else {
    
var v = [];
    
for(attr in o) {
        
if(o[attr] == null) v.push(""" + attr + "": null");
        
else if(typeof o[attr] == "function"); /* skip */
        
else v.push(escapeJSONString(attr) + "" + toJSON(o[attr]));
    }
    
return "{" + v.join(""+ "}";
    }
};


/* JSONRpcClient constructor */

JSONRpcClient 
=
function JSONRpcClient_ctor(serverURL, user, pass, objectID)
{
    
this.serverURL = serverURL;
    
this.user = user;
    
this.pass = pass;
    
this.objectID = objectID;

    
/* Add standard methods */
    
if(this.objectID) {
    
this._addMethods(["listMethods"]);
    
var req = this._makeRequest("listMethods", []);
    } 
else {
    
this._addMethods(["system.listMethods"]);
    
var req = this._makeRequest("system.listMethods", []);
    }
    
var m = this._sendRequest(req);
    
this._addMethods(m);
};


/* JSONRpcCLient.Exception */

JSONRpcClient.Exception 
=
function JSONRpcClient_Exception_ctor(code, message, javaStack)
{
    
this.code = code;
    
var name;
    
if(javaStack) {
    
this.javaStack = javaStack;
    
var m = javaStack.match(/^([^:]*)/);
    
if(m) name = m[0];
    }
    
if(name) this.name = name;
    
else this.name = "JSONRpcClientException";
    
this.message = message;
};

JSONRpcClient.Exception.CODE_REMOTE_EXCEPTION 
= 490;
JSONRpcClient.Exception.CODE_ERR_CLIENT 
= 550;
JSONRpcClient.Exception.CODE_ERR_PARSE 
= 590;
JSONRpcClient.Exception.CODE_ERR_NOMETHOD 
= 591;
JSONRpcClient.Exception.CODE_ERR_UNMARSHALL 
= 592;
JSONRpcClient.Exception.CODE_ERR_MARSHALL 
= 593;

JSONRpcClient.Exception.prototype 
= new Error();

JSONRpcClient.Exception.prototype.toString 
=
function JSONRpcClient_Exception_toString(code, msg)
{
    
return this.name + "" + this.message;
};


/* Default top level exception handler */

JSONRpcClient.default_ex_handler 
=
function JSONRpcClient_default_ex_handler(e) { alert(e); };


/* Client settable variables */

JSONRpcClient.toplevel_ex_handler 
= JSONRpcClient.default_ex_handler;
JSONRpcClient.profile_async 
= false;
JSONRpcClient.max_req_active 
= 1;
JSONRpcClient.requestId 
= 1;


/* JSONRpcClient implementation */

JSONRpcClient.prototype._createMethod 
=
function JSONRpcClient_createMethod(methodName)
{
    
var fn=function()
    {
    
var args = [];
    
var callback = null;
    
for(var i=0;i<arguments.length;i++) args.push(arguments[i]);

/*    TUSCANY change callback to be last arg instead of first to match binding.ajax
    if(typeof args[0] == "function") callback = args.shift();
*/
    
if(typeof args[arguments.length-1== "function") callback = args.pop();

    
var req = fn.client._makeRequest.call(fn.client, fn.methodName,
                          args, callback);
    
if(callback == null) {
        
return fn.client._sendRequest.call(fn.client, req);
    } 
else {
        JSONRpcClient.async_requests.push(req);
        JSONRpcClient.kick_async();
        
return req.requestId;
    }
    };
    fn.client 
= this;
    fn.methodName 
= methodName;
    
return fn;
};

JSONRpcClient.prototype._addMethods 
=
function JSONRpcClient_addMethods(methodNames)
{
    
for(var i=0; i<methodNames.length; i++) {
    
var obj = this;
    
var names = methodNames[i].split(".");
    
for(var n=0; n<names.length-1; n++) {
        
var name = names[n];
        
if(obj[name]) {
        obj 
= obj[name];
        } 
else {
        obj[name]  
= new Object();
        obj 
= obj[name];
        }
    }
    
var name = names[names.length-1];
    
if(!obj[name]) {
        
var method = this._createMethod(methodNames[i]);
        obj[name] 
= method;
    }
    }
};

JSONRpcClient._getCharsetFromHeaders 
=
function JSONRpcClient_getCharsetFromHeaders(http)
{
    
try {
    
var contentType = http.getResponseHeader("Content-type");
    
var parts = contentType.split(/s*;s*/);
    
for(var i =0; i < parts.length; i++) {
        
if(parts[i].substring(08== "charset=")
        
return parts[i].substring(8, parts[i].length);
    }
    } 
catch (e) {}
    
return "UTF-8"/* default */
};

/* Async queue globals */
JSONRpcClient.async_requests 
= [];
JSONRpcClient.async_inflight 
= {};
JSONRpcClient.async_responses 
= [];
JSONRpcClient.async_timeout 
= null;
JSONRpcClient.num_req_active 
= 0;

JSONRpcClient._async_handler 
=
function JSONRpcClient_async_handler()
{
    JSONRpcClient.async_timeout 
= null;

    
while(JSONRpcClient.async_responses.length > 0) {
    
var res = JSONRpcClient.async_responses.shift();
    
if(res.canceled) continue;
    
if(res.profile) res.profile.dispatch = new Date();
    
try {
        res.cb(res.result, res.ex, res.profile);
    } 
catch(e) {
        JSONRpcClient.toplevel_ex_handler(e);
    }
    }

    
while(JSONRpcClient.async_requests.length > 0 &&
      JSONRpcClient.num_req_active 
< JSONRpcClient.max_req_active) {
    
var req = JSONRpcClient.async_requests.shift();
    
if(req.canceled) continue;
    req.client._sendRequest.call(req.client, req);
    }
};

JSONRpcClient.kick_async 
=
function JSONRpcClient_kick_async()
{
    
if(JSONRpcClient.async_timeout == null)
    JSONRpcClient.async_timeout 
=
        setTimeout(JSONRpcClient._async_handler, 
0);
};

JSONRpcClient.cancelRequest 
=
function JSONRpcClient_cancelRequest(requestId)
{
    
/* If it is in flight then mark it as canceled in the inflight map
       and the XMLHttpRequest callback will discard the reply. 
*/
    
if(JSONRpcClient.async_inflight[requestId]) {
    JSONRpcClient.async_inflight[requestId].canceled 
= true;
    
return true;
    }

    
/* If its not in flight yet then we can just mark it as canceled in
       the the request queue and it will get discarded before being sent. 
*/
    
for(var i in JSONRpcClient.async_requests) {
    
if(JSONRpcClient.async_requests[i].requestId == requestId) {
        JSONRpcClient.async_requests[i].canceled 
= true;
        
return true;
    }
    }

    
/* It may have returned from the network and be waiting for its callback
       to be dispatched, so mark it as canceled in the response queue
       and the response will get discarded before calling the callback. 
*/
    
for(var i in JSONRpcClient.async_responses) {
    
if(JSONRpcClient.async_responses[i].requestId == requestId) {
        JSONRpcClient.async_responses[i].canceled 
= true;
        
return true;
    }
    }

    
return false;
};

JSONRpcClient.prototype._makeRequest 
=
function JSONRpcClient_makeRequest(methodName, args, cb)
{
    
var req = {};
    req.client 
= this;
    req.requestId 
= JSONRpcClient.requestId++;

    
var obj = {};
    obj.id 
= req.requestId;
    
if (this.objectID)
    obj.method 
= ".obj#" + this.objectID + "." + methodName;
    
else
    obj.method 
= methodName;
    obj.params 
= args;

    
if (cb) req.cb = cb;
    
if (JSONRpcClient.profile_async)
    req.profile 
= { "submit"new Date() };
    req.data 
= toJSON(obj);

    
return req;
};

JSONRpcClient.prototype._sendRequest 
=
function JSONRpcClient_sendRequest(req)
{
    
if(req.profile) req.profile.start = new Date();

    
/* Get free http object from the pool */
    
var http = JSONRpcClient.poolGetHTTPRequest();
    JSONRpcClient.num_req_active
++;

    
/* Send the request */
    
if (typeof(this.user) == "undefined") {
    http.open(
"POST"this.serverURL, (req.cb != null));
    } 
else {
    http.open(
"POST"this.serverURL, (req.cb != null), this.user, this.pass);
    }

    
/* setRequestHeader is missing in Opera 8 Beta */
    
try { http.setRequestHeader("Content-type""text/plain"); } catch(e) {}

    
/* Construct call back if we have one */
    
if(req.cb) {
    
var self = this;
    http.onreadystatechange 
= function() {
        
if(http.readyState == 4) {
        http.onreadystatechange 
= function () {};
        
var res = { "cb": req.cb, "result"null"ex"null};
        
if (req.profile) {
            res.profile 
= req.profile;
            res.profile.end 
= new Date();
        }
        
try { res.result = self._handleResponse(http); }
        
catch(e) { res.ex = e; }
        
if(!JSONRpcClient.async_inflight[req.requestId].canceled)
            JSONRpcClient.async_responses.push(res);
        
delete JSONRpcClient.async_inflight[req.requestId];
        JSONRpcClient.kick_async();
        }
    };
    } 
else {
    http.onreadystatechange 
= function() {};
    }

    JSONRpcClient.async_inflight[req.requestId] 
= req;
    
    
try {
    http.send(req.data);
    } 
catch(e) {
    JSONRpcClient.poolReturnHTTPRequest(http);
    JSONRpcClient.num_req_active
--;
    
throw new JSONRpcClient.Exception
        (JSONRpcClient.Exception.CODE_ERR_CLIENT, 
"Connection failed");
    }

    
if(!req.cb) return this._handleResponse(http);
};

JSONRpcClient.prototype._handleResponse 
=
function JSONRpcClient_handleResponse(http)
{
    
/* Get the charset */
    
if(!this.charset) {
    
this.charset = JSONRpcClient._getCharsetFromHeaders(http);
    }

    
/* Get request results */
    
var status, statusText, data;
    
try {
    status 
= http.status;
    statusText 
= http.statusText;
    data 
= http.responseText;
    } 
catch(e) {
    JSONRpcClient.poolReturnHTTPRequest(http);
    JSONRpcClient.num_req_active
--;
    JSONRpcClient.kick_async();
    
throw new JSONRpcClient.Exception
        (JSONRpcClient.Exception.CODE_ERR_CLIENT, 
"Connection failed");
    }

    
/* Return http object to the pool; */
    JSONRpcClient.poolReturnHTTPRequest(http);
    JSONRpcClient.num_req_active
--;

    
/* Unmarshall the response */
    
if(status != 200) {
    
throw new JSONRpcClient.Exception(status, statusText);
    }
    
var obj;
    
try {
    eval(
"obj = " + data);
    } 
catch(e) {
    
throw new JSONRpcClient.Exception(550"error parsing result");
    }
    
if(obj.error)
    
throw new JSONRpcClient.Exception(obj.error.code, obj.error.msg,
                      obj.error.trace);
    
var res = obj.result;

    
/* Handle CallableProxy */
    
if(res && res.objectID && res.JSONRPCType == "CallableReference")
    
return new JSONRpcClient(this.serverURL, this.user,
                 
this.pass, res.objectID);

    
return res;
};


/* XMLHttpRequest wrapper code */

/* XMLHttpRequest pool globals */
JSONRpcClient.http_spare 
= [];
JSONRpcClient.http_max_spare 
= 8;

JSONRpcClient.poolGetHTTPRequest 
=
function JSONRpcClient_pool_getHTTPRequest()
{
    
if(JSONRpcClient.http_spare.length > 0) {
    
return JSONRpcClient.http_spare.pop();
    }
    
return JSONRpcClient.getHTTPRequest();
};

JSONRpcClient.poolReturnHTTPRequest 
=
function JSONRpcClient_poolReturnHTTPRequest(http)
{
    
if(JSONRpcClient.http_spare.length >= JSONRpcClient.http_max_spare)
    
delete http;
    
else
    JSONRpcClient.http_spare.push(http);
};

JSONRpcClient.msxmlNames 
= [ "MSXML2.XMLHTTP.5.0",
                 
"MSXML2.XMLHTTP.4.0",
                 
"MSXML2.XMLHTTP.3.0",
                 
"MSXML2.XMLHTTP",
                 
"Microsoft.XMLHTTP" ];

JSONRpcClient.getHTTPRequest 
=
function JSONRpcClient_getHTTPRequest()
{
    
/* Mozilla XMLHttpRequest */
    
try {
    JSONRpcClient.httpObjectName 
= "XMLHttpRequest";
    
return new XMLHttpRequest();
    } 
catch(e) {}

    
/* Microsoft MSXML ActiveX */
    
for (