Szolgáltatásorientált rendszerintegráció SOA-alapú rendszerintegráció Modell alapú fejlesztés Simon Balázs BME IIT, 2011.
Tartalom Modellező keretrendszer UML profile Fejlesztés lépései (C) Simon Balázs, BME IIT, 2011. 2
Modellező keretrendszer (C) Simon Balázs, BME IIT, 2011. 3
Cél Futtatható kódok előállítása Modellezés: UML Automatikus generálás: teljes XSD teljes WSDL BPEL váz C# és Java forráskódok (stub, skeleton) komplett projektek (C) Simon Balázs, BME IIT, 2011. 4
Támogatott/támogatandó eszközök Microsoft Visual Studio 2008, WCF, C# (csak WS) Sun GlassFishESB (WS és BPEL) Oracle JDeveloper 10g, 11g, WebLogic (WS és BPEL) ActiveVOS 5 (BPEL) IBM WebSphere, RAD (WS és BPEL) JBoss (WS) Apache Axis2, CXF (WS) (C) Simon Balázs, BME IIT, 2011. 5
Fejlesztőeszközök támogatottsága Eszköz WS BPEL 1.1 BPEL 2.0 Visual Studio 2008, WCF, C# igen (WCF) - - GlassFishESB igen (JAX-WS) - igen Oracle 10g - igen - Oracle 11g TP4 igen (JAX-WS) - - ActiveVOS 5 - igen igen IBM WebSphere 6.1 - - igen IBM RAD 7 iden (JAX-WS) - - JBoss 5 igen (JAX-WS) - - Apache Axis2 még nem - - Apache CXF még nem - - (C) Simon Balázs, BME IIT, 2011. 6
A keretrendszer részei UML profile az UML szabványnak megfelelően új stereotype-ok és tagged value-k XSD, WSDL és BPEL fájlok előállításához OpenAmeos open-source UML modellező eszköz programozható kódgenerátor SoaCodeGen tanszéken írt kódgenerátor Java alapú Bemenete: az UML modell XMI változata Kimenetei: (három fázis, de egyszerre futnak le) 1. közös, eszközfüggetlen elemek előállítása (XSD, WSDL, BPEL) 2. WS API-knak megfelelő stub-ok és skeleton-ok elkészítése 3. eszközfüggő projektek elkészítése (C) Simon Balázs, BME IIT, 2011. 7
A keretrendszer működése OpenAmeos UML profile UML modell Visual Studio ActiveVOS GlassFishESB Projects Oracle JDeveloper JBoss IBM WID, RAD Mof2Xmi Project Generator Project.xmi XSD, WSDL, BPEL Generator Common Schema (XSD) WSDL BPEL Stub Generator Stubs WCF JAX-WS (C) Simon Balázs, BME IIT, 2011. 8
UML profile (C) Simon Balázs, BME IIT, 2011. 9
UML profile-ok XSD: namespace sequence, choice, all egyszerű öröklődés WSDL: absztrakt: message, porttype konkrét: binding, service BPEL-hez: partnerlinktype BPEL: process (C) Simon Balázs, BME IIT, 2011. 10
XSD profile (C) Simon Balázs, BME IIT, 2011. 11
WSDL profile (C) Simon Balázs, BME IIT, 2011. 12
BPEL profile (C) Simon Balázs, BME IIT, 2011. 13
Névterek, csomagok: UML
Névterek, csomagok: XSD common\schema\wsapisample.xsd: <?xml version="1.0" encoding="utf-8"?> <xs:schema elementformdefault="qualified" xmlns:xs="http://www.w3.org/2001/xmlschema" targetnamespace="http://ik.bme.hu/wsapi" xmlns="http://ik.bme.hu/wsapi" xmlns:wsapi="http://ik.bme.hu/wsapi"> </xs:schema>
Névterek, csomagok: WSDL common\wsdl\wsapisample.wsdl: <?xml version="1.0" encoding="utf-8"?> <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/xmlschema" targetnamespace="http://ik.bme.hu/wsapi" xmlns="http://ik.bme.hu/wsapi" xmlns:wsapi="http://ik.bme.hu/wsapi"> <wsdl:types> <xs:schema> <xs:import namespace="http://ik.bme.hu/wsapi" schemalocation="../schema/wsapisample.xsd"/> </xs:schema> </wsdl:types> </wsdl:definitions>
Névterek, csomagok: WCF stubs\wcf\wsapiprj\wsapiprjlib.cs: namespace WsApi.Sample { [ServiceContract(Namespace = "http://ik.bme.hu/wsapi")]... [DataContract(Namespace = "http://ik.bme.hu/wsapi")]... }
Névterek, csomagok: JAX-WS stubs\jaxws\wsapi\sample\package-info.java: @javax.xml.bind.annotation.xmlschema( namespace = "http://ik.bme.hu/wsapi", elementformdefault = javax.xml.bind.annotation.xmlnsform.qualified) package wsapi.sample;
Saját típus: UML
Saját típus: XSD common\schema\wsapisample.xsd: <xs:schema...> <xs:element name="person" nillable="true" type="wsapi:person"/> <xs:complextype name="person"> <xs:sequence> <xs:element name="age" type="xs:int"/> <xs:element name="name" nillable="true" type="xs:string"/> </xs:sequence> </xs:complextype> </xs:schema>
Saját típus: WCF stubs\wcf\wsapiprj\wsapiprjlib.cs: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.Runtime.Serialization; namespace WsApi.Sample { [DataContract(Name = "Person", Namespace = "http://ik.bme.hu/wsapi")] public class Person { [DataMember(IsRequired = true)] public int Age { get; set; } [DataMember(IsRequired = true)] public string Name { get; set; } } }
Saját típus: JAX-WS (JAXB) stubs\jaxws\wsapi\sample\person.java: package wsapi.sample; import javax.xml.bind.annotation.xmlaccesstype; import javax.xml.bind.annotation.xmlaccessortype; import javax.xml.bind.annotation.xmlelement; import javax.xml.bind.annotation.xmltype; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "Person", proporder = { "age", "name" }) public class Person { @XmlElement(name = "Age") protected int age; @XmlElement(name = "Name", required = true, nillable = true) protected String name; } // + getter/setter metódusok
Contract: UML
Contract: XSD (1) common\schema\wsapisample.xsd: <?xml version="1.0" encoding="utf-8"?> <xs:schema...> <xs:element name="sayhello" nillable="true" type="wsapi:sayhello"/> <xs:complextype name="sayhello"> <xs:sequence> <xs:element name="name" nillable="true" type="wsapi:person"/> </xs:sequence> </xs:complextype> <xs:element name="sayhelloresponse" nillable="true" type="wsapi:sayhelloresponse"/> <xs:complextype name="sayhelloresponse"> <xs:sequence> <xs:element name="sayhelloresult" nillable="true" type="xs:string"/> </xs:sequence> </xs:complextype>
Contract: XSD (2) common\schema\wsapisample.xsd:... <xs:element name="sayhelloasync" nillable="true" type="wsapi:sayhelloasync"/> <xs:complextype name="sayhelloasync"> <xs:sequence> <xs:element name="name" nillable="true" type="wsapi:person"/> </xs:sequence> </xs:complextype> </xs:schema>
Contract: WSDL (1) common\wsdl\wsapisample.wsdl: <?xml version="1.0" encoding="utf-8"?> <wsdl:definitions... xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl">... <wsdl:message name="ihello_sayhello_inputmessage"> <wsdl:part name="parameters" element="wsapi:sayhello"/> </wsdl:message> <wsdl:message name="ihello_sayhello_outputmessage"> <wsdl:part name="parameters" element="wsapi:sayhelloresponse"/> </wsdl:message> <wsdl:message name="ihello_sayhelloasync_inputmessage"> <wsdl:part name="parameters" element="wsapi:sayhelloasync"/> </wsdl:message>...
Contract: WSDL (2) common\wsdl\wsapisample.wsdl:... <wsdl:porttype name="ihello"> <wsdl:operation name="sayhello"> <wsdl:input message="wsapi:ihello_sayhello_inputmessage" wsaw:action="http://ik.bme.hu/wsapi/ihello/sayhello" /> <wsdl:output message="wsapi:ihello_sayhello_outputmessage" wsaw:action="http://ik.bme.hu/wsapi/ihello/sayhelloresponse"/> </wsdl:operation> <wsdl:operation name="sayhelloasync"> <wsdl:input message="wsapi:ihello_sayhelloasync_inputmessage" wsaw:action="http://ik.bme.hu/wsapi/ihello/sayhelloasync" /> </wsdl:operation> </wsdl:porttype> </wsdl:definitions>
Contract: WCF stubs\wcf\wsapiprj\wsapiprjlib.cs: [ServiceContract(Namespace = "http://ik.bme.hu/wsapi")] public interface IHello { [OperationContract] string SayHello(Person name); [OperationContract(IsOneWay = true)] void SayHelloAsync(Person name); }
Contract: JAX-WS stubs\jaxws\wsapi\sample\ihello.java:... @WebService(name = "IHello", targetnamespace = "http://ik.bme.hu/wsapi") public interface IHello { @WebMethod(operationName = "SayHello") public String sayhello(@webparam(name = "name") Person name); } @WebMethod(operationName = "SayHelloAsync") @Oneway public void sayhelloasync(@webparam(name = "name") Person name);
throws: MathFault Fault: UML
Fault: XSD (1) common\schema\wsapisample.xsd: <?xml version="1.0" encoding="utf-8"?> <xs:schema...> <xs:element name="divide" nillable="true" type="wsapi:divide"/> <xs:complextype name="divide"> <xs:sequence> <xs:element name="left" type="xs:double"/> <xs:element name="right" type="xs:double"/> </xs:sequence> </xs:complextype> <xs:element name="divideresponse" nillable="true" type="wsapi:divideresponse"/> <xs:complextype name="divideresponse"> <xs:sequence> <xs:element name="divideresult" type="xs:double"/> </xs:sequence> </xs:complextype>...
Fault: XSD (2) common\schema\wsapisample.xsd:... <xs:element name="mathfault" nillable="true" type="wsapi:mathfault"/> <xs:complextype name="mathfault"> <xs:sequence> <xs:element name="reason" type="xs:string"/> </xs:sequence> </xs:complextype> </xs:schema>
Fault: WSDL (1) common\wsdl\wsapisample.wsdl: <wsdl:definitions...>... <wsdl:message name="icalculator_divide_inputmessage"> <wsdl:part name="parameters" element="wsapi:divide"/> </wsdl:message> <wsdl:message name="icalculator_divide_outputmessage"> <wsdl:part name="parameters" element="wsapi:divideresponse"/> </wsdl:message> <wsdl:message name="mathfault_faultmessage"> <wsdl:part name="parameters" element="wsapi:mathfault"/> </wsdl:message>...
Fault: WSDL (2) common\wsdl\wsapisample.wsdl:... <wsdl:porttype name="icalculator"> <wsdl:operation name="divide"> <wsdl:input message="wsapi:icalculator_divide_inputmessage" wsaw:action="http://ik.bme.hu/wsapi/icalculator/divide" /> <wsdl:output message="wsapi:icalculator_divide_outputmessage" wsaw:action="http://ik.bme.hu/wsapi/icalculator/divideresponse"/> <wsdl:fault name="mathfault" message="wsapi:mathfault_faultmessage" wsaw:action="http://ik.bme.hu/wsapi/icalculator/divide/fault/mathfault"/> </wsdl:operation> </wsdl:porttype> </wsdl:definitions>
Fault: WCF (1) stubs\wcf\wsapiprj\wsapiprjlib.cs: [DataContract(Name = "MathFault", Namespace = "http://ik.bme.hu/wsapi")] public class MathFault { [DataMember(IsRequired = true, EmitDefaultValue = false)] public string Reason {get; set; } }
Fault: WCF (2) stubs\wcf\wsapiprj\wsapiprjlib.cs: [ServiceContract(Namespace = "http://ik.bme.hu/wsapi")] public interface ICalculator { [OperationContract( Action = "http://ik.bme.hu/wsapi/icalculator/divide", ReplyAction = "http://ik.bme.hu/wsapi/icalculator/divideresponse")] [FaultContract(typeof(MathFault), Action = "http://ik.bme.hu/wsapi/icalculator/divide/fault/mathfault", Name = "MathFault")] double Divide(double left, double right); }
Fault: JAX-WS (1) stubs\jaxws\wsapi\sample\mathfault.java:... @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "MathFault", proporder = { "reason" }) public class MathFault { @XmlElement(name = "Reason", required = true) protected String reason; // + getter-ek, setter-ek }
Fault: JAX-WS (2) stubs\jaxws\wsapi\sample\mathfaultfaultmessage.java:... @WebFault(name = "MathFault", targetnamespace = "http://ik.bme.hu/wsapi") public class MathFaultFaultMessage extends Exception { private MathFault faultinfo; public MathFaultFaultMessage(String message, MathFault faultinfo) { super(message); this.faultinfo = faultinfo; } public MathFaultFaultMessage(String message, MathFault faultinfo, Throwable cause) { super(message, cause); this.faultinfo = faultinfo; } public MathFault getfaultinfo() { return faultinfo; } }
Fault: JAX-WS (3) stubs\jaxws\wsapi\sample\icalculator.java:... @WebService(name = "ICalculator", targetnamespace = "http://ik.bme.hu/wsapi") public interface ICalculator { @WebMethod(operationName = "Divide", action = "http://ik.bme.hu/wsapi/icalculator/divide") @Action(input = "http://ik.bme.hu/wsapi/icalculator/divide", output = "http://ik.bme.hu/wsapi/icalculator/divideresponse", fault = { @FaultAction(className = MathFault.class, value = "http://ik.bme.hu/wsapi/icalculator/divide/fault/mathfault") }) public double divide( @WebParam(name = "left") double left, @WebParam(name = "right") double right) throws MathFaultFaultMessage; }
Binding: UML
Binding: WSDL common\wsdl\wsapisamplebinding.wsdl: <?xml version="1.0" encoding="utf-8"?> <wsdl:definitions...>... <wsdl:binding name="icalculator_calculatorbinding_binding" type="wsapi:icalculator"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="divide"> <soap:operation style="document" soapaction="http://ik.bme.hu/wsapi/icalculator/divide" /> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="mathfault"> <soap:fault name="mathfault" use="literal"/> </wsdl:fault> </wsdl:operation> </wsdl:binding> </wsdl:definitions>
Service: UML
Service: WCF Calculator.cs: public class Calculator : ICalculator { public double Divide(double left, double right) { if (right == 0) { throw new FaultException<MathFault>( new MathFault() { Reason = "Division by zero." }); } return left / right; } }
Service: JAX-WS Calculator.java:... @WebService(endpointInterface = "wsapi.sample.icalculator") public class Calculator implements ICalculator { @Override public double divide(double left, double right) throws MathFaultFaultMessage { if(right == 0) { MathFault fault = new MathFault(); fault.setreason("division by zero."); throw new MathFaultFaultMessage("Error", fault); } return left / right; } }
Fejlesztés lépései (C) Simon Balázs, BME IIT, 2011. 45
Fejlesztés lépései 1. Modellezés (OpenAmeos: UML) 2. Modell exportálása: (OpenAmeos: Mof2Xmi) 3. Kódgenerátor lefuttatása (SoaCodeGen) 4. Előállított projekt megnyitása az fejlesztőeszközben 5. Hiányzó kódrészek kitöltése 6. Projekt telepítése az alkalmazásszerverre (C) Simon Balázs, BME IIT, 2011. 46
Modellezés: 1. új projekt (C) Simon Balázs, BME IIT, 2011. 47
Modellezés: 2. projekt neve (C) Simon Balázs, BME IIT, 2011. 48
Modellezés: 3. profile-ok kiválasztása (C) Simon Balázs, BME IIT, 2011. 49
Modellezés: 4. osztálydiagramok rajzolása (C) Simon Balázs, BME IIT, 2011. 50
Modellezés: 5. exportálás XMI-ba (C) Simon Balázs, BME IIT, 2011. 51
Kódgenerálás A keletkezett XMI átmásolása a generátor könyvtárába A generátor indítása: paraméter: az XMI fájl neve kiterjesztés nélkül Példa: SoaCodeGenerator.bat Eva (C) Simon Balázs, BME IIT, 2011. 52
Eredmény common: XSD-k, WSDL-ek és BPEL-ek schema: az XSD-k wsdl: a WSDL-ek bpel: a BPEL-ek stubs: az eszközspecifikus stub-ok wcf: a WCF stub-jai jaxws: a JAX-WS stub-jai projects: az eszközspecifikus projektek ActiveBPEL IbmRad75 IbmWid61 JBoss5 OpenESB OracleJDeveloper10g OracleJDeveloper11g VisualStudio2008 (C) Simon Balázs, BME IIT, 2011. 53
Projekt megnyitása a Visual Studio-ban (C) Simon Balázs, BME IIT, 2011. 54
Implementálás: Apeh namespace EvaSample { public class Apeh : IApeh { // Az eredmény a kapott adószám tízszerese lesz: public long GetBevetel(string adoszam) { long result; if (long.tryparse(adoszam, out result)) return result * 10; else return 0; } } } (C) Simon Balázs, BME IIT, 2011. 55
Implementálás: Cégbíróság namespace EvaSample { public class Cegbirosag : ICegbirosag { // A c:\temp\cegbirosag.txt-ben egy új bejegyzés keletkezik public bool SetVallalkozasForma(string adoszam, string forma) { using(streamwriter output = new StreamWriter(@"c:\Temp\cegbirosag.txt", true)) { output.writeline("ido: {0}", DateTime.Now); output.writeline("adoszam={0}, Forma={1}", adoszam, forma); output.writeline(); } return true; } } } (C) Simon Balázs, BME IIT, 2011. 56
Projekt megnyitása az ActiveVOS-ban (C) Simon Balázs, BME IIT, 2011. 57
Implementálás: Folyamat (C) Simon Balázs, BME IIT, 2011. 58
Telepítés Eszközönként a szokásos módon Visual Studio 2008: IIS-re átmásolni a projektet Konfigurálni alkalmazásként ActiveVOS: PDD már generálva van BPRD-t és BPR-t kell csak elkészíteni Telepítés a beépített szerverre: web-szolgáltatáson keresztül (C) Simon Balázs, BME IIT, 2011. 59
Tesztelés Visual Studio 2008-ból konzol alkalmazással c:\temp\cegbirosag.txt tartalma: Ido: 9/19/2008 6:38:16 PM Adoszam=123456, Forma=EVA (C) Simon Balázs, BME IIT, 2011. 60
Tesztelés ActiveVOS konzolon megjelent a két folyamat: (C) Simon Balázs, BME IIT, 2011. 61
Öszefoglalás 1. Modellezés (OpenAmeos: UML) 2. Modell exportálása: (OpenAmeos: Mof2Xmi) 3. Kódgenerátor lefuttatása (SoaCodeGen) 4. Előállított projekt megnyitása az fejlesztőeszközben 5. Hiányzó kódrészek kitöltése 6. Projekt telepítése az alkalmazásszerverre (C) Simon Balázs, BME IIT, 2011. 62