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
igen (WCF)
-
-
igen (JAX-WS)
-
igen
-
igen
-
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
-
-
Visual Studio 2008, WCF, C#
GlassFishESB Oracle 10g Oracle 11g TP4
(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
Projects
Visual Studio ActiveVOS GlassFishESB
Mof2Xmi
Oracle JDeveloper JBoss IBM WID, RAD
Project Generator
Project.xmi
XSD, WSDL, BPEL Generator
Common Schema (XSD) WSDL
Stubs Stub Generator
WCF JAX-WS
BPEL (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: <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">
Névterek, csomagok: WSDL
common\wsdl\WsApiSample.wsdl: <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"/>
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"/>
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 import import import
javax.xml.bind.annotation.XmlAccessType; javax.xml.bind.annotation.XmlAccessorType; javax.xml.bind.annotation.XmlElement; 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: <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:element name="SayHelloResponse" nillable="true" type="wsapi:SayHelloResponse"/> <xs:complexType name="SayHelloResponse"> <xs:sequence> <xs:element name="SayHelloResult" nillable="true" type="xs:string"/>
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"/>
Contract: WSDL (1)
common\wsdl\WsApiSample.wsdl: <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 name="IHello_SayHello_OutputMessage"> <wsdl:part name="parameters" element="wsapi:SayHelloResponse"/> <wsdl:message name="IHello_SayHelloAsync_InputMessage"> <wsdl:part name="parameters" element="wsapi:SayHelloAsync"/> ...
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 name="SayHelloAsync"> <wsdl:input message="wsapi:IHello_SayHelloAsync_InputMessage" wsaw:Action="http://ik.bme.hu/WsApi/IHello/SayHelloAsync" />
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); }
Fault: UML
throws: MathFault
Fault: XSD (1)
common\schema\WsApiSample.xsd: <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:element name="DivideResponse" nillable="true" type="wsapi:DivideResponse"/> <xs:complexType name="DivideResponse"> <xs:sequence> <xs:element name="DivideResult" type="xs:double"/> ...
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"/>
Fault: WSDL (1)
common\wsdl\WsApiSample.wsdl: <wsdl:definitions ...> ... <wsdl:message name="ICalculator_Divide_InputMessage"> <wsdl:part name="parameters" element="wsapi:Divide"/> <wsdl:message name="ICalculator_Divide_OutputMessage"> <wsdl:part name="parameters" element="wsapi:DivideResponse"/> <wsdl:message name="MathFault_FaultMessage"> <wsdl:part name="parameters" element="wsapi:MathFault"/> ...
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"/>
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: <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:output> <soap:body use="literal"/> <wsdl:fault name="MathFault"> <soap:fault name="MathFault" use="literal"/>
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