SCA (Service Component Architecture)
โต้โผก็คือ IBM, SAP, IONA, BEA, Oracle, ... (ยกเว้น SUN)
ผลักดันเพื่อเป็นตัวเสริมทัพ SOA (Service Oriented Architecture)
ท้าวความ SOA นิดหนึ่งก่อน
SOA จะมี nature อย่างหนึ่งก็คือ
มันเป็น coarse-grained service
nature ของ coarse-grained service ก็คือ
มี method ให้ใช้ไม่มาก, parameter ที่่รับส่งมักจะเป็นแบบ document oriented style
ตัว SCA ก็คือ Framework ที่เราสามารถใช้
fine grained component
ประกอบขึ้นเป็น SOA Service (coarse-grained service)
(ผู้ไม่คุ้นกับ java คงจะเริ่มบ่นว่า ยุ่งจังโว้ย)
ผมเป็นพวกต้องเห็น code ก่อนจึงจะเข้าใจ concept
ดีที่ตอนนี้มี Incubator project ที่ชื่อ Tuscany
submit code เข้าไปใน apache แล้ว
ก็เลยมีตัวอย่างให้ดู
ลองดูตัวอย่าง HelloWorld service ก่อน
เริ่มด้วยการ define interface ก่อนว่า helloworld มี method อะไรให้เรียกใช้
public interface HelloWorldService {
public String getGreetings(String name);
}
จากนั้นก็ตามด้วย implementation
@Service(HelloWorldService.class)
public class HelloWorldServiceComponentImpl implements HelloWorldService {
/*
* @see org.apache.tuscany.samples.helloworld.HelloWorldServiceComponent#getGreetings()
*/
public String getGreetings(String name) {
return "Hello " + name;
}
}
เริ่มสังเกตุเห็น key concept ของ SCA แล้ว
- Service Implementation มีลักษณะเป็น POJO (plain old java object)
- ใช้ Annotation เข้ามากำหนด Nature
เมื่อมี interface กับ implementation แล้ว
ก็มาถึง module definition
module ก็คือ group ของ component ที่ deploy ร่วมกัน
(ในกรณี helloword เรามี component เดียว)
<module xmlns="http://www.osoa.org/xmlns/sca/0.9" xmlns:v="http://www.osoa.org/xmlns/sca/values/0.9"
name="sampleHelloworld">
<component name="HelloWorldServiceComponent">
<implementation.java class="org.apache.tuscany.samples.helloworld.HelloWorldServiceComponentImpl"/>
</component>
</module>
ตรงนี้ยังมองไม่เห็นอะไรมากนัก เพราะมันยังมีแค่ component เดียวอยู่
ไว้กลับมาดูอีกทีตอนมีหลาย component
มาดูตอนใช้งานบ้าง
ส่วนของ client ที่เรียกใช้ จะมีหน้าตาดังนี้
public class HelloWorldClient {
public static final void main(String[] args) throws Exception {
// Obtain Tuscany runtime
TuscanyRuntime tuscany = new TuscanyRuntime("hello", null);
// Start the runtime
tuscany.start();
// Obtain SCA module context.
ModuleContext moduleContext = CurrentModuleContext.getContext();
// Locate the HelloWorld service component and invoke it
HelloWorldService helloworldService = (HelloWorldService)
moduleContext.locateService("HelloWorldServiceComponent");
String value = helloworldService.getGreetings("World");
System.out.println(value);
// Stop the runtime
tuscany.stop();
}
}
จะเห็นว่ามี concept ของ Runtime
ตัว SCA เป็นแค่ spec ดังนั้นต้องมี implementation ถึงจะทำงานได้จริง
Tuscany ก็คือ implementation ที่ว่า
นอกจากนี้ จะเห็นได้ว่าเราต้อง lookup service จาก module
ลองดูตัวอย่าง Module definition ที่มีหลาย component บ้าง
<module xmlns="http://www.osoa.org/xmlns/sca/0.9" xmlns:v="http://www.osoa.org/xmlns/sca/values/0.9"
name="sampleHelloworld">
<component name="HelloWorldServiceComponent">
<implementation.java class="org.apache.tuscany.samples.helloworldmc.HelloWorldServiceComponentImpl"/>
<references>
<v:greetingPrefix>GreetingPrefixComponent</v:greetingPrefix>
<v:greetingSuffix>GreetingSuffixComponent</v:greetingSuffix>
</references>
<properties>
<v:greetingMiddle>SCA</v:greetingMiddle>
</properties>
</component>
<component name="GreetingPrefixComponent">
<implementation.java class="org.apache.tuscany.samples.helloworldmc.GreetingPortionProviderImpl"/>
<properties>
<v:greetingPortion>Hello</v:greetingPortion>
</properties>
</component>
<component name="GreetingSuffixComponent">
<implementation.java class="org.apache.tuscany.samples.helloworldmc.GreetingPortionProviderImpl"/>
<properties>
<v:greetingPortion>World</v:greetingPortion>
</properties>
</component>
</module>
เห็นแล้วอย่าพึ่งถอดใจ ปรับสายตาสักนิด จะเห็นว่า
มันใช้หลักการเดียวกับ Spring นั่นคือ Dependency Injection
การร้อย component หรือการ config component ใน SCA
จะใช้หลักการเดียวกับ spring
หลายคนจะเริ่มสงสัยแล้วว่า มันเป็น webservice อย่างไร
กรณีที่เราต้องการให้เป็น web service ก็ต้องมีการ กำหนด entry point
ใน Module ด้วย
<module xmlns="http://www.osoa.org/xmlns/sca/0.9" xmlns:v="http://www.osoa.org/xmlns/sca/values/0.9"
name="sampleHelloworld">
<entryPoint name="HelloWorldService">
<interface.wsdl interface="http://helloworldaxis.samples.tuscany.apache.org#HelloWorldServiceImpl"/>
<binding.ws port="http://helloworldaxis.samples.tuscany.apache.org#helloworld"/>
<reference>HelloWorldServiceComponent/HelloWorldService</reference>
</entryPoint>
<component name="HelloWorldServiceComponent">
<implementation.java class="org.apache.tuscany.samples.helloworldws.HelloWorldServiceComponentImpl"/>
</component>
<import.wsdl
location="wsdl/helloworld.wsdl"
namespace="http://helloworldaxis.samples.tuscany.apache.org"/>
</module>
จะเห็นประเด็นหนึ่งที่ว่า definition ของ entrypoint ได้มาจาก
file wsdl โดยตรง
และมี keyword ที่เรียกว่า "binding"
spec ของ SCA เปิดโอกาสให้เรา binding ในรูป protocol อื่นได้เช่น
<entryPoint name="HelloWorldService">
<interface.java interface="org.apache.tuscany.samples.helloworldjsonrpc.HelloWorldService"/>
<jsonrpc:binding.jsonrpc/>
<reference>HelloWorldServiceComponent/HelloWorldService</reference>
</entryPoint>
อันนี้เป็นการ binding service เป็น JSON rpc service
ที่ขาดไม่ได้คือ key สำคัญของ SCA ไม่ได้อยู่ที่ model ของ Component อย่างเดียว
แต่อยู่ที่ SDO (Service Data Object) ด้วย
SDO เข้ามาเป็น key ได้อย่างไร
จำประโยคที่ว่า "Coarse Grain Service พึงมี parameter style เป็น Document Style"
SDO ก็คือ Data Model ที่ช่วยให้เราจัดการกับ Document Style นี้ได้ง่ายขึ้น
เพราะ เราสามารถ pass document ในรูป SDO ไปให้ Party อื่นๆ
เมื่อ Party นั้นๆ ทำการแก้ไขรายการใน document เสร็จ (เช่น fill-in, append, delete)
ก็จะส่ง document นั้นคืนมา
ซึ่งเราสามารถใช้ feature ของ SDO เข้าไปดูเฉพาะ
dataset ที่เกิดการเปลี่ยนแปลงได้
เช่นหาเฉพาะ list item ที่ถูก เพิ่ม หรือ ลบ ออกจาก document
ลองดูตัวอย่าง test case ของ SDO
เริ่มด้วยการสร้าง DataObject
(เห็นมันเป็น object อย่างนี้ แต่เวลาที่มันถูก serialize เพื่อรับ/ส่ง
ระหว่าง program แล้ว มันจะถูก serialize ในรูป xml file)
DataGraph dataGraph = SDOUtil.createDataGraph();
DataObject quote = dataGraph.createRootObject("http://www.example.com/simple", "Quote");
กรณีที่ต้องการบันทึกการเปลี่ยนแปลง
ก็จะใช้ method
beginLogging
กับ endLogging
เข้ามาช่วย
ChangeSummary changeSummary = dataGraph.getChangeSummary();
changeSummary.beginLogging();
quote.setString("companyName", "FlyByNightTechnology");
quote.setBigDecimal("price", new BigDecimal("1000.0"));
quote.setBigDecimal("open1", new BigDecimal("1000.0"));
...
DataObject child = quote.createDataObject("quotes");
child.setBigDecimal("price", new BigDecimal("2000.0"));
changeSummary.endLogging();
ถ้าอยากเห็นว่า IBM นำ SDO ไปประยุกต์ได้อย่างมีประสิทธิภาพอย่างไร
ต้องดู FacesClient Components Developer's Guide
ที่สำคัญคือ IBM เริ่มออก sdo api ที่อยู่บนภาษาอื่นออกมาแล้ว
มี SDO for php ที่สามารถใช้บน php ได้