Ready, Set, Go - Getting started with Tuscany

安装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  ==   1 return   " /u000 "   +  hex;
    
else   if (hex.length  ==   2 return   " /u00 "   +  hex;
    
else   if (hex.length  ==   3 return   " /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( 0 8 ==   " 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  ( var  i = 0 ;i  <  JSONRpcClient.msxmlNames.length; i ++ ) {
    
try  {
        JSONRpcClient.httpObjectName 
=  JSONRpcClient.msxmlNames[i];
        
return   new  ActiveXObject(JSONRpcClient.msxmlNames[i]);
    } 
catch  (e) {}
    }

    
/*  None found  */
    JSONRpcClient.httpObjectName 
=   null ;
    
throw   new  JSONRpcClient.Exception( 0 " Can't create XMLHttpRequest object " );
};

bindingjsonrpc 
=   " loaded " ;
 
现在项目工程如下:
 
启动服务
编写Build文件:
< project  name ="store"  default ="compile" >
    
< property  name ="test.class"  value ="launch.Launch"   />
    
< property  name ="test.jar"    value ="sample-store.jar"   />
    
    
< target  name ="init" >
        
< mkdir  dir ="target/classes" />
    
</ target >
    
    
< target  name ="compile"  depends ="init" >
        
< javac  srcdir ="src"
               destdir
="target/classes"
               debug
="on"
               source
="1.6"
               target
="1.6"
               encoding
="UTF-8" >
            
< classpath >
                
< pathelement  location ="lib/tuscany-sca-manifest.jar" />
            
</ classpath >
        
</ javac >  
        
< copy  todir ="target/classes" >
            
< fileset  dir ="resources" />
        
</ copy >
        
< jar  destfile ="target/${test.jar}"  basedir ="target/classes" >
            
< manifest >
                
< attribute  name ="Main-Class"  value ="${test.class}"   />  
            
</ manifest >
        
</ jar >         
    
</ target >     
    
    
< target  name ="run-classes" >
        
< java  classname ="${test.class}"
              fork
="true" >
            
< classpath >
                
< pathelement  path ="target/classes" />
                
< pathelement  location ="lib/tuscany-sca-manifest.jar" />
            
</ classpath >
        
</ java >
    
</ target >
    
    
< target  name ="run" >
        
< java  classname ="${test.class}"
              fork
="true" >
            
< classpath >
                
< pathelement  path ="target/${test.jar}" />
                
< pathelement  location ="lib/tuscany-sca-manifest.jar" />
            
</ classpath >
        
</ java >         
    
</ target >     
    
    
< target  name ="clean" >
        
< delete  quiet ="true"  includeemptydirs ="true" >
            
< fileset  dir ="target" />
        
</ delete >
    
</ target >
</ project >
现在我们将要启动我们创建的服务。新建一个launch包,在该包内新建一个Launch类,选中“public static void main(String[] args)”以为该类创建一个main方法,代码如下:
package  launch;
import  org.apache.tuscany.sca.host.embedded.SCADomain;
public   class  Launch {
    
public   static   void  main(String[] args)  throws  Exception {
        System.out.println(
" Starting ... " );
        SCADomain scaDomain 
=  SCADomain.newInstance( " store.composite " );
        System.out.println(
" store.composite ready for big business !!! " );
        System.out.println();
        System.in.read();
        scaDomain.close();
    }
}
现在项目如下:
 
祝贺你,你完成了你的第一个集成服务应用程序,现在是时候启动它了。
 
使用服务
在本步骤你将启动刚刚创建的服务应用。
首先,选中刚刚创建的 Launch类,然后在右键菜单中选中Run As Java Application,那么Tuscany就会开始将store添加到域(domain)。
Eclipse的控制台将要输出如下信息:
 
接下来,就可以通过浏览器查看了:
译者注:经译者测试,只有在 Firefox浏览器上本程序的添加商品以及其他功能才正常,在IE浏览器上开始商品列表亦不能显示,在修正了binding-atom.js脚本的一些错误以后才显示出来,但提交功能仍不正常,经反复测试,发现在store.html文件中的shoppingCart_getResponse()函数中,var entries = feed.getElementsByTagName("entry");没有取得值:
function  shoppingCart_getResponse(feed) {
        
if  (feed  !=   null ) {
            
var  entries  =  feed.getElementsByTagName( " entry " );              
            
var  list  =   "" ;
            alert(entries.length);
            
for  ( var  i = 0 ; i < entries.length; i ++ ) {
                
var  item  =  entries[i].getElementsByTagName( " content " )[ 0 ].firstChild.nodeValue;
                list 
+=  item  +   '  <br> ' ;
            }
            document.getElementById(
" shoppingCart " ).innerHTML  =  list;
            document.getElementById(
' total ' ).innerHTML  =  feed.getElementsByTagName( " subtitle " )[ 0 ].firstChild.nodeValue;
        }
    }
 
在 IE中如下:
 
下面是 firefox中,运行正常,原因尚在分析中。
 
你可以在 Catalog中选择水果,然后放入你的购物篮中。
注意:当你首次添加项目时浏览器会要求你输入用户名和密码,这时都输入 admin。
 
因为 ShoppingCart服务是通过Atom绑定的方式进行绑定的,也可以点击(feed)连接通过ATOM feed查看购物卡内容:
 
返回前一页:
 
最后,你可以结账以完成购物:
选择“ Apache Tuscany SCA Tools”,并在接下来的窗口一路点击Next,直到点击Finish为止
 
接受该插件的使用协议( Plugin License)
 
接下来点击“ Install All”
 
当被要求重启 Eclipse的时候,点击“Yes”按钮
 
创建你的第一个集成服务应用程序
下面的图就是我们将要创建的应用的组件图

该应用是由四个服务组成的,这个应用是一个在线商店,这里有一个目录服务,你可以通过它取得项目名单,依靠currencyCode属性来判断是以美元还是欧元提供项目价格,目录服务本身不去做货币换算的工作,相反它引用了一个CurrencyConverter服务去完成这个工作。接下来,这里还有一个ShoppingCart服务,从目录选择了的项目可以被加进去(购物车),它是使用REST实现的;Catalog使用的是一个JSONRPC绑定,ShoppingCart呢则是通过ATOM进行绑定,最后,就是提供给用户的、基于浏览器的界面服务的Store组件了,Store服务组件分别通过JSONRPCATOM绑定使用CatalogShoppingCart服务。

 

创建一个Java工程

这一步你要在Eclipse中建立一个Java工程,点击工具栏上的New Java Project按钮 来打开新建工程的对话框,接下来输入store作为工程名称,并选择Create separate

folders for sources and class files

点击下一步按钮,在接下来的窗口打开Libraries选项卡,点击Add Library...按钮以添加Tuscany Libraray到工程中:

最后,点击Finish按钮结束工程创建。

 

构建服务

首先,创建两个包目录,以便在接下来的步骤中存放服务的实现。选择“store”工程,点击工具栏上的新建Java包按钮 启动创建包对话框。接下来,输入services作为包名,点击Finish按钮关闭对话框。

 

重复刚才的步骤,创建另外一个名为 ufservices的包,工程现在看起来应该类似这跟样子:

记下来,会在services包内放入普通的服务,ufservices内是界面相关服务。

 

Catalog

现在,准备创建Catalog服务的接口和实现。

选择“services”包,接下来在工具栏的下拉菜单中点击“New Java Class” 按钮 和“New Java Interface”按钮 ,在弹出的对话框中以“Catalog”作为接口名,并点击Finish关闭对话框,这时在Java编辑器中就会打开新增的Java接口,将下面这段Java接口代码Copy-Paste到编辑器内:

package  services;
import  org.osoa.sca.annotations.Remotable;
@Remotable
public   interface  Catalog {
    String[] get();
}

再次选中“services”包,点击“New Java Class”按钮 ,在弹出的对话框中以“CatalogImpl”作为类的名字,将“Catalog”作为该类的实现接口,点击Finish完成。

Java编辑器中会打开我们新增的类,将下面的代码复制过去:

 

package  services;
import  java.util.ArrayList;
import  java.util.List;
import  org.osoa.sca.annotations.Init;
import  org.osoa.sca.annotations.Property;
import  org.osoa.sca.annotations.Reference;
public   class  CatalogImpl  implements  Catalog {
    @Property
    
public  String currencyCode  =   " USD " ;
    @Reference
    
public  CurrencyConverter currencyConverter;
    
private  List < String >  catalog  =   new  ArrayList < String > ();
    @Init
    
public   void  init() {
        String currencySymbol 
=  currencyConverter.getCurrencySymbol(currencyCode);
        catalog.add(
" Apple -  "   +  currencySymbol  +
        currencyConverter.getConversion(
" USD " , currencyCode,  2.99f ));
        catalog.add(
" Orange -  "   +  currencySymbol  +
        currencyConverter.getConversion(
" USD " , currencyCode,  3.55f ));
        catalog.add(
" Pear -  "   +  currencySymbol  +
        currencyConverter.getConversion(
" USD " , currencyCode,  1.55f ));
    }
    
public  String[] get() {
        String[] catalogArray 
=   new  String[catalog.size()];
        catalog.toArray(catalogArray);
        
return  catalogArray;
    }
}

 

当完成这些步骤以后, store项目看起来会类似这样:

 

注意, CatalogImpl上面有一个红叉,因为它引用了我们还没由实现的CurrencyConverter接口。
 
CurrencyConverter

在这一步,我们将创建CurrencyConverter的接口和实现,首先,按照之前的方式建立接口和类文件,并将下面的代码复制过去:

package  services;
import  org.osoa.sca.annotations.Remotable;
@Remotable
public   interface  CurrencyConverter {
    
public   float  getConversion(String fromCurrenycCode,
    String toCurrencyCode, 
float  amount);
    
public  String getCurrencySymbol(String currencyCode);
}
 
下面,我们来创建上面这跟接口的实现类 CurrencyConverterImpl:
package  services;
public   class  CurrencyConverterImpl  implements  CurrencyConverter {
    
public   float  getConversion(String fromCurrencyCode,
        String toCurrencyCode, 
float  amount) {
        
if  (toCurrencyCode.equals( " USD " ))
            
return  amount;
        
else               if  (toCurrencyCode.equals( " EUR " ))
                
return  amount * 0.7256f ;
        
return   0 ;
    }
    
public  String getCurrencySymbol(String currencyCode) {
        
if  (currencyCode.equals( " USD " ))
            
return   " $ " ;
        
else
            
if  (currencyCode.equals( " EUR " ))
                
return   " " ;
        
return   " ? " ;
    }
}
 
现在,项目看起来是这样:
 
ShoppingCart
在这里我们要创建 ShoppingCart的实现类。
仍然在 services包内创建我们的实现类,代码如下:
package  services;
import  java.util.Date;
import  java.util.HashMap;
import  java.util.Map;
import  java.util.UUID;
import  org.apache.tuscany.sca.binding.feed.collection.Collection;
import  org.apache.tuscany.sca.binding.feed.collection.NotFoundException;
import  com.sun.syndication.feed.atom.Content;
import  com.sun.syndication.feed.atom.Entry;
import  com.sun.syndication.feed.atom.Feed;
import  com.sun.syndication.feed.atom.Link;
public   class  ShoppingCartImpl  implements  Collection {
    
//  needs to change to instance var once conversation scope works
     private   static  Map < String, Entry >  cart  =   new  HashMap < String, Entry > ();
    
public  Feed getFeed() {
        Feed feed 
=   new  Feed();
        feed.setTitle(
" shopping cart " );
        Content subtitle 
=   new  Content();
        subtitle.setValue(
" Total :  "   +  getTotal());
        feed.setSubtitle(subtitle);
        feed.getEntries().addAll(cart.values());
        
return  feed;
    }
    
public  Entry get(String id)  throws  NotFoundException {
        
return  cart.get(id);
    }
    
public  Entry post(Entry entry) {
        String id 
=   " cart- "   +  UUID.randomUUID().toString();
        entry.setId(id);
        Link link 
=   new  Link();
        link.setRel(
" edit " );
        link.setHref(
""   +  id);
        entry.getOtherLinks().add(link);
        link 
=   new  Link();
        link.setRel(
" alternate " );
        link.setHref(
""   +  id);
        entry.getAlternateLinks().add(link);
        entry.setCreated(
new  Date());
        cart.put(id, entry);
        
return  entry;
    }
        
public   void  put(String id, Entry entry)  throws  NotFoundException {
        entry.setUpdated(
new  Date());
        cart.put(id, entry);
    }
    
public   void  delete(String id)  throws  NotFoundException {
        
if  (id.equals( "" ))
            cart.clear();
        
else
            cart.remove(id);
    }     
private  String getTotal() {
        
float  total  =   0 ;
        String symbol 
=   "" ;
        
if  ( ! cart.isEmpty()) {
            Entry entry 
=  cart.values().iterator().next();
            String item 
=  ((Content)entry.getContents().get( 0 )).getValue();
            symbol 
=  item.substring(item.indexOf( " - " ) + 2 , item.indexOf( " - " ) + 3 );
        }
        
for  (Entry entry : cart.values()) {
            String item 
=  ((Content)entry.getContents().get( 0 )).getValue();
            total 
+=  Float.valueOf(item.substring(item.indexOf( " - " ) + 3 ));
        }
        
return  symbol  +  String.valueOf(total);
    }
}
注意:由于 Tuscany的会话支持目前还实现,购物篮在这里通过一个hack来实现,cart被定义成一个静态域。
目前,项目看起来如下:
 
Store
这里将创建一个用户界面服务,通过浏览器为我们创建的其他服务提供交互的接口和界面。在ufservices内新建一个文件store.html,代码如下:
< html >
< head >
< title > Store </ TITLE >

< script  type ="text/javascript"  src ="store.js" ></ script >

< script  language ="JavaScript" >

    
// Reference
    catalog  =  ( new  JSONRpcClient( " ../Catalog " )).Catalog;
    
// Reference
    shoppingCart  =   new  AtomClient( " ../ShoppingCart " );


    
function  catalog_getResponse(items) {
        
var  catalog  =   "" ;
        
for  ( var  i = 0 ; i < items.length; i ++ )
            catalog 
+=   ' <input name="items" type="checkbox" value=" '   +
                        items[i] 
+   ' "> '   +  items[i] +   '  <br> ' ;
        document.getElementById(
' catalog ' ).innerHTML = catalog;
    }

    
function  shoppingCart_getResponse(feed) {
        
if  (feed  !=   null ) {
            
var  entries  =  feed.getElementsByTagName( " entry " );
            
var  list  =   "" ;
            
for  ( var  i = 0 ; i < entries.length; i ++ ) {
                
var  item  =  entries[i].getElementsByTagName( " content " )[ 0 ].firstChild.nodeValue;
                list 
+=  item  +   '  <br> ' ;
            }
            document.getElementById(
" shoppingCart " ).innerHTML  =  list;
            document.getElementById(
' total ' ).innerHTML  =  feed.getElementsByTagName( " subtitle " )[ 0 ].firstChild.nodeValue;
        }
    }
    
function  shoppingCart_postResponse(entry) {
        shoppingCart.get(
"" , shoppingCart_getResponse);
    }


    
function  addToCart() {
        
var  items   =  document.catalogForm.items;
        
var  j  =   0 ;
        
for  ( var  i = 0 ; i < items.length; i ++ )
            
if  (items[i].checked) {
                
var  entry  =   ' <entry xmlns="http://www.w3.org/2005/Atom"><title>cart-item</title><content type="text"> ' + items[i].value + ' </content></entry> '
                shoppingCart.post(entry, shoppingCart_postResponse);
                items[i].checked 
=   false ;
            }
    }
    
function  checkoutCart() {
        document.getElementById(
' store ' ).innerHTML = ' <h2> '   +
                
' Thanks for Shopping With Us!</h2> ' +
                
' <h2>Your Order</h2> ' +
                
' <form name="orderForm" action="store.html"> ' +
                    document.getElementById(
' shoppingCart ' ).innerHTML +
                    
' <br> ' +
                    document.getElementById(
' total ' ).innerHTML +
                    
' <br> ' +
                    
' <br> ' +
                    
' <input type="submit" value="Continue Shopping"> ' +
                
' </form> ' ;
        shoppingCart.del(
"" null );
    }
    
function  deleteCart() {
        shoppingCart.del(
"" null );
        document.getElementById(
' shoppingCart ' ).innerHTML  =   "" ;
        document.getElementById(
' total ' ).innerHTML  =   "" ;
    }

    catalog.get(catalog_getResponse);
    shoppingCart.get(
"" , shoppingCart_getResponse);
</ script >

</ head >

< body >
< h1 > Store </ h1 >
  
< div  id ="store" >
       
< h2 > Catalog </ h2 >
       
< form  name ="catalogForm" >
        
< div  id ="catalog"   ></ div >
        
< br >
        
< input  type ="button"  onClick ="addToCart()"   value ="Add to Cart" >
       
</ form >

     
< br >

       
< h2 > Your Shopping Cart </ h2 >
       
< form  name ="shoppingCartForm" >
        
< div  id ="shoppingCart" ></ div >
        
< br >
        
< div  id ="total" ></ div >
        
< br >
        
< input  type ="button"  onClick ="checkoutCart()"  value ="Checkout" >
        
< input  type ="button"  onClick ="deleteCart()"  value ="Empty" >
           
< href ="../ShoppingCart/" > (feed) </ a >
    
</ form >
  
</ div >
</ body >
</ html >
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值