ServiceOrientedJavaBusinessIntegrationCopyright©2008PacktPublishingAllrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.
Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthor,PacktPublishing,noritsdealersordistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.
PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.
Firstpublished:March2008
ProductionReference:1040308
PublishedbyPacktPublishingLtd.
32LincolnRoad
Olton
Birmingham,B276PA,UK.
ISBN978-1-847194-40-4
www.packtpub.com
CoverImagebyVinayakChittar([email protected])
CreditsAuthor
BinildasC.A.
Reviewers
RajeshRV
RajeshWarrier
AcquisitionEditor
BansariBarot
DevelopmentEditor
VedPrakashJha
TechnicalEditor
DellaPradeep
EditorialTeamLeader
MithilKulkarni
ProjectManager
AbhijeetDeobhakta
ProjectCoordinator
AboliMendhe
Indexers
HemanginiBari
MonicaAjmera
Proofreader
AngieButcher
ProductionCoordinator
ShantanuZagade
AparnaBhagat
Coverwork
ShantanuZagade
AbouttheAuthorBinildasC.A.providesTechnicalArchitectureconsultancyforITsolutions.Hehasover13yearsofITexperience,mostlyinMicrosoftandSuntechnologies.DistributedComputingandServiceOrientedIntegrationarehismainstreamskills,withextensivehands-onexperienceinJavaandC#.NETprogramming.BinilholdsaBTech.degreeinMechanicalEngineeringfromCollegeofEngineering,Trivandrum(www.cet.ac.in)andanMBAinSystemsManagementfromInstituteofManagement,Kerala(www.imk.ac.in).Awell-knownandahighlysoughtafterthoughtleader,Binilhasdesignedandbuiltmanyhighlyscalablemiddle-tierandintegrationsolutionsforseveraltop-notchclientsincludingFortune500companies.HehasbeenpreviouslyemployedbymultipleITconsultingfirmsincludingIBSSoftwareServices(www.ibsplc.com)andTataConsultancyServices(www.tcs.com)andcurrentlyworksforInfosysTechnologies(www.infosys.com)asaPrincipalArchitectwhereheheadstheJ2EEArchitectsgroupservicingCommunicationsServiceProviderclients.
BinilisaSunCertifiedProgrammer(SCJP),Developer(SCJD),BusinessComponentDeveloper(SCBCD)andEnterpriseArchitect(SCEA),MicrosoftCertifiedProfessional(MCP)andOpenGroup(TOGAF8)CertifiedEnterpriseArchitecturePractitioner.HeisalsoaLicensedZapthinkArchitect(LZA)inSOA.BesidesTechnicalArchitectureBinil
alsopracticesEnterpriseArchitecture.
Whennotinsoftware,BinilspendstimewithwifeSowmya&daughterAnnin'God'sOwnCountry',Kerala(www.en.wikipedia.org/wiki/Kerala).BinildoeslongdistancerunningandisanationalmedalistinPowerLifting.YoumaycontactBinilatbiniljava@[email protected].
AcknowledgementFirstandForemost,IwouldthankGodwhohasalwaysshoweredhischoicestblessingsonme.IthankHimforallthathehasdoneforme.
IwouldliketothankPACKTandeveryoneIworkedwith—PriyankaBaruah,BansariBarot,PatriciaWeir,AboliMendhe,BhushanPangaonkar,VedPrakashJha,DellaPradeepandothers.TheyworkedveryhardwiththeaggressivescheduleIproposedonthisbook,andItrulydoappreciatetheircontributions.
Next,I'dliketothanktheTechnicalReviewersofourbook,RajeshR.V.andRajeshR.Warrier.Withoutthem,youwouldn'tseethetextasitappearshere.Thankyouforyourthoroughreviewofthescriptsandtestingofthecode.Yourreviewswereveryobjectiveinpointingoutissuesandhelpingmetocomeupwiththeevenbetterchapters.
ThisbookwouldhaveneverbeenpossibleifwereitnotfortheexcellentcolleaguesatIBS(otherthanthereviewers)whomIhaveworkedwithandlearnedfrom.ThemostimportantofthemarePrasanthGNair,ShyamSankarS,SherryCK,JayanPandAmrithaMathewM.ThanksareduetoVKMathewsforprovidingallofustheopportunity.IwouldalsoliketothankRajasekharC.andAjmalKhanwhoprovidedmetherightchallengesattherighttime.
SpecialthanksareduetoDr.SrinivasPadmanabhuni,PrincipalResearcher,WebServices/SOACentreofExcellence,SoftwareEngineeringandTechnologyLabs,Infosysforhisguidanceandhelp.
IwouldliketothankmywifeandbestfriendSowmyaforbeingaconstantsourceofinspirationinmylife.AlsomysweetlittledaughterAnn,Irememberallthosemomentswhenyouweresodesperatetoplaywithmeandtogooutfor'dinner'withpappaandamma,butIcouldnotlookbeyondmylaptopscreen.Bothofyouaremyangels,thanksforeverything,especiallyforbeinginmylife.
AmassivethanksmustgotomyMomandDad—AzhakammaandChristudas—whohavesupportedtheirwaywardsonthroughgoodandleantimes,andhavegiveneverythingandaskedfornothing.Ithanktherestofmyfamilyfortheirsupportandfriendship—mysisterBinithaandfamily,mywife'smother,Pamala,andfatherHubertfortheirunconditionalencouragementandloveinhelpingmefindtheenergytocompletethisbook.
IwouldalsoliketothankRamavarmaRforsupportingmethroughhisconsultancy,MacJavaB.
Thereweremanyotherswhoplayedtheirparttoo.Mostimportantofthemarethecreatorsoftheframeworksthathaveinspiredmetowritethisbook.ThankyoufortheJBIspecificationandspecialthankstotheServiceMixdeveloperandusercommunity.
Last,it'snecessarytothankyou,thereader,forchoosingtobuythisbook.IunderstandthatyouhaveaspecificintentioninchoosingtoreadthisbookandIhopeItakeonlytheminimumrequiredtimefromyourbusyschedulestoserveyourrequirements.
AbouttheReviewersRajeshRVreceivedhisComputerEngineeringdegreefromtheUniversityofCochin,India.HejoinedtheJEEcommunityduringtheearlydaysofEJB(1.0)andfullydedicatedhistimeincoretechnicalactivitiesinandaroundJava,JEE.Duringthecourseasasolutionarchitect,hehasworkedonmanylargescalemissioncriticalprojects,includingtheNewGenerationPassengerReservationSystem(400+ManYears)andNextGenerationCargoReservationSystem(300+ManYears),intheAirlinedomain.RajeshisalsoSunCertifiedJavaEnterpriseArchitectandBEACertifiedWeblogicAdministrator.
RajeshiscurrentlyworkingwithEmiratesAirlinesITDivisionbasedinDubaiandhisworkismainlyinConsulting,ApplicationFrameworkdevelopment,TechnologyEvaluationsandSOArelatedtopics.
AllmythanksgoestomywifeSarithaforsupportingmeandlovingmeeventhoughIbookedalotofpersonaltimetoreviewthisbook.
RajeshWarrier,currentlyworkingasoneoftheleadsystemarchitectsinEmiratesGroupIT,hasaround10yearsexperienceintheindustryworkingwithcompanieslikeSunMicrosystems.Hehasbeenresponsibleforarchitectinganddesigningmanymissioncriticalenterpriseapplicationsusing
cuttingedgetechnologies.Heiscurrentlyworkingasanarchitectandmentorforthenewgenerationcargosystemfortheemiratesairlines,developedcompletelyusingJEE.
PrefaceYou'reallinthebusinessofsoftwaredevelopment.Someofyouarearchitectsanddeveloperswhilefewothersaretechnologymanagersandexecutives.Formanyofyou,ESBisencroachingandJBIisstillanunknown—ariskpreviouslyavoidedbutnowfoundtobeinescapable.LetustamethesebuzzwordsinthecontextofSOAandIntegration.
Whileyoudothedaytodayprogrammingforsolvingbusinessproblems,youwillbegeneratingbusinesscodeaswellasbusinessintegrationcode.ThetraditionalJava/J2EEAPIsprovideyouwithenoughtoolsandframeworkstodothebusinesscoding.Thebusinesscodewillhelpyoutoimplementabusinessservicesuchascreatingordersorfindingproducts.Onthecontrary,businessintegrationcodewirestogethermultipleapplicationsandsystemstoprovideseamlessinformationflow.Itdealswithpatternsofinformationexchangeacrosssystemsandservices,amongotherthings.ThisiswherethenewJavaAPIforIntegration—JavaBusinessIntegration(JBI)seeksattention.
JBIprovidesacollaborationframeworkwhichhasstandardinterfacesforintegrationcomponentsandprotocolstopluginto,thusallowingtheassemblyofServiceOrientedIntegration(SOI)frameworksfollowingtheEnterpriseServiceBus(ESB)pattern.JBIisbasedonJSR208,whichisanextensionofJava2EnterpriseEdition(J2EE).Thebookfirst
discussesthevariousintegrationapproachesavailableandintroducesESB,whichisanewarchitecturalpatternwhichcanfacilitateintegratingservices.Indoingso,wealsointroduceServiceMix,anApacheOpenSourceJavaESB.Thusforeachofthesubsequentchapters,welimitourdiscussiontoamajorconcernwhichwecanaddressusingESBandthenalsoshowcasethiswithsampleswhichyoucanrunusingServiceMix.Ifyouareapersonwithanon-Javabackground,thebookstillbenefitsyousincemostoftheintegrationwiringhappensinXMLconfigurationfiles.
TheaimofthisbookistoprepareanarchitectordeveloperforbuildingintegrationsolutionsusingESB.Tothatend,thisbookwilltakeapracticalapproach,emphasizinghowtogetthingsdoneinServiceMixwithcode.Onoccasions,wewilldelveintothetheoreticalaspectsofESB,andsuchdiscussionswillalwaysbesupplementedwithenoughrunningsamples.Thebook,thus,attemptstodistillsomeoftheknowledgethathasemergedoverthelastdecadeintherealmofJavaIntegration.Quitedifferentfromtheotherbooksintherelatedtopics,youdon'tneeda4GBRAMorsomeheavy,vendorspecificIDE/Workshopstorunthesamples.Instead,getsetwiththelatestJDKandatexteditorandfewotherlightweightframeworksincludingTomcatandyouarereadytogo.Enoughaboutthehype,supplementwithwhatyou'veheardwithsomesubstanceandcode.
HappyReading!
WhatThisBookCoversChapter1beginswithaquicktouronEnterpriseIntegrationandtheassociatedissuessothatyoucanbetterunderstandtheproblemwhichwearetryingtosolve,ratherthanfollowingasolutionforanunknownproblem.WealsointroduceEnterpriseServiceBus(ESB)architectureandcompareandcontrastthatwithotherintegrationarchitectures.
Chapter2introducesJavaBusinessIntegration(JBI)andinspectstheneedforanotherstandardforBusinessIntegration,andalsolooksintothedetailsonwhatthisstandardisallabout.
Chapter3introducesServiceMix,whichisanopensourceESBplatformintheJavaprogramminglanguage,builtfromthegroundupwithJBIAPIsandprinciples.ItrunsthroughafewotherESBproductsalso.
Chapter4looksathowwehavebeenbindingserviceslocallyorremotelyevenbeforetheESBbecamepopular.ThechapterwilldemonstratehowtunnelingusingconventionalJ2EEtoolswillhelptoexposeeventechnology-specificAPIservices.AnexampleofsuchaserviceisanEJBservicetobeexposedthroughfirewallsoverHTTPsothattheservicebecomestechnologyagonistic.
Chapter5introducesXFire,whichisanewgenerationJava
SOAPframeworktoeasilyexposewebservices.HerewedemonstratetheintegrationcapabilitiesoftheXFire.ThenwecandointegrationusingXFirewithintheJBIArchitecturealso.
Chapter6teachesyouJBIpackaginganddeployment.Aftergoingthroughthischapterthereaderwillbeabletobuild,package,anddeployintegrationartifactsasstandardJBIpackagesintotheJBIcontainer.
Chapter7teachsyouhowtocreateyourowncomponentsanddeploythemontotheJBIcontainer.ThischaptervisitsthecoreAPIfromtheServiceMixaswellasfromtheJBIspecificationwhichwillfunctionasusefulhelperclassesusingwhichyoucandevelopintegrationcomponentsquickly.
Chapter8showsyouhowtobindEnterpriseJavaBeanscomponentstotheESB.EJBistheDistributedComponentparadigmintheJava-J2EEworldandtheindustryhasalotinvestedinthistechnology.CoexistingserviceswiththosecomponentswillhelpyoutoreusethoseexistinginvestmentssothatwecancontinuebuildingnewsystemsbasedonhigherlevelsofSOAmaturity.
Chapter9showsPOJOBindingusingJSR181totheESB.POJOcomponentscanbeeasilyexposedasWSDL-compliantservicestotheJBIbus.
Chapter10illustrateshowtobindthewebservicestotheServiceMixESB,thuscreatingawebservicesgatewayattheESBlayer.
Chapter11looksathowJavaMessageService(JMS),whichisaplatformdependentmessagingtechnology,canincreasetheQOSfeaturesofwebservicesbymakingwebservicesaccessiblethroughtheJMSchannel.
Chapter12introducesJavaXMLbindingandXStream,whichisasimpleopensourcelibrarytoserializetheJavaobjectstoXMLandbackagain.WewillshowtheXStreamintegrationwithESBdemonstratingstreamingofdataacrossthebus.
Chapter13visitstheJDKProxyclassesandthenexplainstheJBIProxyindetailwithexamples.WeshowapracticaluseoftheJBIProxy—ProxyingtheexternalwebservicesintheJBIbus.
Chapter14explainsversioningintheSOAcontextandexplainsvariousstrategiesandapproachestoversioningservices.ItalsoexplainsanddemonstratesaversioningsampleleveragingthetargetNamespaceattribute.Versioningservices,especiallyversioningofwebservices,isatopicofheateddiscussioninmanyforumsandsites.
Chapter15explainsthattheEAIpatternsarenuggetsofadvicemadeoutofaggregatingbasicMessageExchangePatternelementstosolvefrequentlyrecurringintegrationproblems.WecanlookatEAIpatternsasdesignpatternsforsolvingintegrationproblems.ThischapterwilldemonstratemanyofthecommonEAIpatterns.
Chapter16looksintoasampleusecase.OneoftheusefulapplicationsofESBistoprovidea"ServicesWorkbench"
whereinwhichwecanusevariousintegrationpatternsavailabletoaggregateservicestocarryoutthebusinessprocesses.
Chapter17visitsafewselectedQOSfeaturessuchasTransactions,Security,Clustering,andManagementwhichcanimpacttheprogramminganddeploymentaspectsusingESB.
WhatYouNeedforThisBookToinstallandrunmostofthesamplesmentionedinthisbookallyouneedisthefollowing:
LatestJavaSDK(JDK)installedinyourmachine.
ApacheOpenSourceEnterpriseServiceBus—ServiceMix.
ApacheAntbuildtool.
Asimpletexteditor,likeTextpad.
Anyothersoftwarerequiredismentionedwhichisdownloadablefreefromthenet.
WhoisThisBookforThisbookisaimedatJavadevelopersandintegrationarchitectswhowanttobecomeproficientwithJavaBusinessIntegration(JBI)standard.TheyareexpectedtohavesomeexperiencewithJavaandtohavedevelopedanddeployedapplicationsinthepast,butneednopreviousknowledgeofJBI.ThebookcanalsobeusefultoanyonewhohasbeenstrugglingtounderstandESBandhowitdiffersfromotherarchitecturesandtounderstanditspositioninSOA.
ThisbookprimarilytargetsITprofessionalsinthefieldofSOAandIntegrationsolutions—inotherwords,intermediatetoadvancedusers.Youarelikelytofindthebookusefulifyoufallintoanyofthefollowingcategories:
Aprogrammer,designerorarchitectinJavawhowantstolearnandcodeinJBIorESB.
Aprogrammer,designerorarchitectwhodoesn'tnormallycodeinJavacanstillbenefitfromthisbook,sincewe'assembleintegrationcomponents'usingXMLwithlittletonoJavacode.
AnITManageroranOfficerwhoknowswellaboutSOAorSOIbutwanttoseesomethingincode(youcanadornyourflashypresentationswithsomelivecodetoo).
ConventionsInthisbook,youwillfindanumberofstylesoftextthat
distinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestyles,andanexplanationoftheirmeaning.
Therearethreestylesforcode.Codewordsintextareshownasfollows:"Forexample,insidethe<component>tagyoucanconfigurepropertiesonthecomponent."
Ablockofcodewillbesetasfollows:
<targetname="run">
<javaclassname="HttpInOutClient"fork="yes"
failonerror="true">
<classpathrefid="classpath">
<arg
value="http:/localhost:8912/EsbServlet/hello/">
<argvalue="HttpSoapRequest.xml">
</java>
</target>
Anycommand-lineinputandoutputiswrittenasfollows:
cdch03\Servlet
ant
Newtermsandimportantwordsareintroducedinabold-typefont.Wordsthatyouseeonthescreen,inmenusordialogboxesforexample,appearinourtextlikethis:"Thecomponentsbeinginitialized,inourcase,includetrace,timer,httpGetData,andhttpReceiver."
NOTENOTE
Importantnotesappearinaboxlikethis.
NOTENOTE
Tipsandtricksappearlikethis.
ReaderFeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook,whatyoulikedormayhavedisliked.Readerfeedbackisimportantforustodeveloptitlesthatyoureallygetthemostoutof.
Tosendusgeneralfeedback,[email protected],makingsuretomentionthebooktitleinthesubjectofyourmessage.
Ifthereisabookthatyouneedandwouldliketoseeuspublish,pleasesendusanoteintheSUGGESTATITLEformonwww.packtpub.comoremailsuggest@packtpub.com.
Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideonwww.packtpub.com/authors.
CustomerSupportNowthatyouaretheproudownerofaPacktbook,wehavea
numberofthingstohelpyoutogetthemostfromyourpurchase.
DownloadingtheExampleCodefortheBookVisithttp://www.packtpub.com/files/code/4404_Code.zip,todirectlydownladtheexamplecode.
Thedownloadablefilescontaininstructionsonhowtousethem.
ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontents,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeintextorcode—wewouldbegratefulifyouwouldreportthistous.Bydoingthisyoucansaveotherreadersfromfrustration,andhelptoimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,reportthembyvisitinghttp://www.packtpub.com/support,selectingyourbook,clickingontheSubmitErratalink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerrataareaddedtothelistofexistingerrata.Theexistingerratacanbeviewedbyselectingyourtitlefromhttp://www.packtpub.com/support.
Questions
Youcancontactusatquestions@packtpub.comifyouarehavingaproblemwithsomeaspectofthebook,andwewilldoourbesttoaddressit.
Chapter1.WhyEnterpriseServiceBusToday'senterpriseisnotconfinedtothephysicalboundariesofanorganization.OpensystemsandanopenITinfrastructurestrivestoprovideinteroperabilitynotonlybetweenplatforms,runtimes,andlanguages,butalsoacrossenterprises.Whenourconcernsshiftfromnetworkedsystemstonetworkedenterprises,awholelotofopportunitiesopenuptointeractwithenterpriseapplications.Whetheritisfortradingpartnerstocollaboratethroughtheirback-endsystems,orformultichanneldeploymentswhereconsumerscanuseawholelotofuseragentslikewebandmobilehandsets,theopportunitiesareendless.Thisalsointroducestheissuesandconcernstobeaddressedbynetwork,integration,andapplicationarchitects.Today,companiesthathavebeenbuiltthroughmergersorrapidexpansionshaveLineofBusinesses(LOB)andsystemswithinasingleenterprisethatwerenotintendedtointeracttogether.Moreoftenthannottheseinteractionsfailandarediscredited.
Let'sbeginwithaquicktourofenterpriseintegrationandtheassociatedissuessothatwecanbetterunderstandtheproblemwhichwearetryingtosolve,ratherthanfollowasolutionforanunknownproblem.Attheendofthischapter,youshouldbeinapositiontoidentifywhatwearetryingtoaimwiththisbook.WealsointroduceEnterpriseServiceBus(ESB)
architecture,andcompareandcontrastitwithotherintegrationarchitectures.ThenwecanbetterunderstandhowJavaBusinessIntegration(JBI)helpsustodefineESB-basedsolutionsforintegrationproblems.
Inthischapterwewillcoverthefollowing:
Problemsfacedbytoday'senterprises
EnterpriseApplicationIntegration(EAI)
Differentintegrationarchitectures
ESB
Compareandcontrastservicebusandmessagebus
NeedforanESB-basedarchitecture
Boundary-LessOrganizationJackWelch,ofGeneralElectric(GE),inventedtheboundary-lessorganization.Meaningthat,organizationsshouldnotonlybeboundary-less,butshouldalsobemadepermeable."Integratedinformation"and"integratedaccesstointegratedinformation"aretwokeyfeaturesthatanyenterpriseshouldaimfor,inordertoimprovetheirorganizationalbusinessprocesses.Boundary-lessdoesn'tmeanthatorganizationhasnoboundaries;itmeansthatthere'sasmoothandefficientflowofinformationacrossboundaries.Whileenterpriseportalsandwebservicesgiveanewfaceforthisemergingparadigm,theskeletonofthis"openenterprise"isprovidedbyanopenITinfrastructure.ThefleshisprovidedbyemergingtrendsinEnterpriseApplicationIntegration(EAI)practice.
Letusbrieflyvisitafewselectedissuesfacedbytoday'senterprises.
MultipleSystemsInahomebusinessorinsmallscaleventures,westartupwithsystemsandapplicationsinsiloswhichcatertotheentiresetup.Whenthebusinessgrows,weaddmoreverticals,whicharefunctionallyseparatedentitieswithinthesameorganization.Itgoeswithoutsayingthat,eachoftheseverticalsorLOBwillhavetheirownsystems.Peopleaskwhytheyhavedifferentsystems.Theanswerisbecausetheyaredoingfunctionallydifferentoperationsinanenterpriseandhencetheyneedsystemscarryingoutdifferentfunctionalityforthem.Forexample,anHRsystemwillmanageandmaintainemployeerelateddatawhereasthemarketingrelationswilluseCustomerRelationshipManagement(CRM)systems.ThesesystemsmaynotbeinterconnectedandhenceimpedeinformationflowacrossLOBs.Addingtothis,eachLOBwillhavetheirownbudgetingandcostconstraintswhichdeterminehowoftensystemsareupgradedorintroduced.
NoCanonicalDataFormatMultipleLOBswillhavetheirownsystems,andhencetheirowndataschemas,andawayofaccessingthedata.Thisleadstoduplicationofdata,whichinturnleadstomultipleservicesprovidingviewsforthesameentityindifferentways.
Let'sconsidertheexampleshowninthefollowingfigure.
ThereisoneLOBsystem,ProductInformationSystem,whichwillkeeptrackofcustomerswhohaveregisteredtheirinterestforaparticularproductorservice.AnotherLOBsystem,EventRegistrationSystem,willprovidemembershipmanagementtoolstocustomers,forasalesdiscountprogram.SalesInformationSystemwillhavetotrackallcustomerswhohaveregisteredtheirinterestforanyupcomingproductsorservices.Thus,wecanseethereisnounifiedviewoftheCustomerentityattheenterprise-level.EachLOBwillhaveitsownsystemsandtheirownviewofCustomer.SomewillhavemoreattributesfortheCustomer,whileothersafew.NowthequestioniswhichsystemownstheCustomerentity?Rather,howdoweaddressthedatastewardshipissue(Thisisrepresentedinthefigureusingthesymbols"?"and"?")?
NOTENOTE
Datastewardshiprolesarecommonwhenorganizationsattempttoexchangedata,preciselyandconsistently,betweencomputersystems,andreusedata-relatedresourceswherethestewardisresponsibleformaintainingadataelementinametadataregistry.
Autonomous,butFederatedNowthequestionishowlongcanthesesystemsremain
isolated?Rather,canwebringallthesesystemsunderacentral,singlepointofcontrol?Thefactis,systemscannotremainisolated,andalsotheycannotbecontrolledcentrally.Thisisbecauseeverysystemneedsdatafromevery(ormost)othersystems.Canwethenintegrateeverythingtogetherintoasinglebigsystemsothatwedon'thavetheproblemofintegrationatall?Thequestionseemstempting,butthisisanalogoustoattemptingtoboilseawater.
Differentdepartmentsorverticalswithinthesameorganizationneedautonomyandsodotheirsystems.Withouttherequiredlevelofautonomy,thereisnofreedomwhichwillhinderinnovation.Constantinnovationisthekeytosuccess,inanywalkoflife.So,departmentsandtheirsystemsneedtobeautonomous.But,sincetheyrequireeachother'sdata,theyneedtointegrate.Thisleadstothenecessityforafarmofautonomoussystems,whichareallfederatedtotherequiredleveltofacilitateinformationflow.
Thefollowingfigurerepresentssystemsthatareautonomous,butfederatedtofacilitateinformationflow:
IntranetversusInternetIntegratingdifferentfunctionaldepartmentswithinanorganizationisnotabighurdle,sinceeverythingisunderthecontroloftheorganization.Butthepicturechangesthemomenttheorganizationgrowsbeyondacertainlimit.Twentyfirstcenturyorganizationsaregrowingbeyondasinglelocation;manyofthemaretrulyglobalorganizations.Theyhaveoperationsaroundtheglobe,inmultiplecountries,withmultiplelegal,technical,andoperationalenvironments.ThegoodnewsisthatwehavetechnologieslikeInternet,WideAreaNetworks,andVirtualPrivateNetworksforconnectivity.Thismeansglobalorganizationswillhavetheirsystemsfederatedacrosstheglobe.Allthesesystemswillevolveduetoconstantinnovationandbusinesschanges.Theyhavetointegrateacrossthefirewall,andnoteveryprotocolandformatcanbeeasilytraversedacrossthefirewall.
TradingPartnersOrganizationsconductbusinesswithotherorganizations.Anonlineretailer'ssystemhastopartnerwithitswholesaler'sinventorysystems.Thesesystemsarenotfederatedinanymannerduetothefactthattheybelongtomultipleorganizations.Thereexistsnofederationduetothecompetitivenaturebetweenorganizationstoo.Buttheyhavetocollaborate;otherwisethereisnobusinessatall.So,informationhastoflowacrossorganizationalsystemsintheInternet.Thisiswhatwemeanbyapermeableorganizationboundarywhichallowsforconstantinformationexchangeon
24X7bases,withadequateQualityofService(QOS)features.Thusthenecessityistoextendtheenterpriseovertheedge(firewall),andthisactivityhastohappenbasedonpre-plansandnotasanafterthought.
ThefollowingfigureexplainsatradingpartnerssystemthatisnotfederatedbuttheinformationflowisthroughtheInternet:
IntegrationKnowinglyorunknowingly,applicationsandsystemshavebeenbuiltoverdecadesinsilos,anditistheneedofthedayfortheseapplicationsandsystemstointerchangedata.Atvariouslevelsdependinguponthelevelofcontrol,thedatacanbeinterchangedatmultiplelayers,protocols,andformats.
Thereseemstobeageneraltrendof"Technologyoftheday"solutionsandsystemsinmanyorganizations.Neitherthistrendisgoingtoend,nordoweneedtoturnbackatthem.Instead,weneedtomanagetheeverchangingheterogeneitybetweensystems.
NOTENOTE
Applicationandsystemportfolioentropyincreaseswithtechnologyinnovation.
Idon'tknowifthereisaglobalmovementtobringstandardizationtoinnovationintechnology.Thisisbecausethemomentweintroducerulesandregulationstoinnovation,itisnolongeraninnovation.Thisstatementismade,evenafteracknowledgingvariousworldwidestandardbodies'aimandefforttoreducesystemandapplicationentropy.Afewyearsback,CommonObjectRequestBrokerProtocol's(CORBA)promisewastostandardizebinaryprotocolinterfacesothatanysystemscouldinteroperate.IfwelookatCORBAatthispoint,wecanseethatCORBAhasnotattaineditspromise,thatdoesn'tmeanthatweneedtothrowawayallthosesystemsintroducedduringthe90'sbecausewecannotintegrate.
EnterpriseApplicationIntegrationDavidS.LinthicumdefinedEAIas:
Theunrestrictedsharingofdataandbusinessprocessesamonganyconnectedapplicationsanddatasourcesinthe
enterprise.
Thisisasimple,straightforwarddefinition.Inmyentirecareer,IhavebeenfortunateenoughtoparticipateinmuchnewgenerationITsystemdevelopmentfordomainssuchasAirline,Healthcare,andCommunications.Mostofthetime,I'vebeenwritingeitheradaptersbetweensystems,ornegotiatingandformalizingdataformatsbetweendesperatesystems.Iknowthisisnotbecausetheformersystem'sarchitectshaven'tputalongtermvisiontotheirsystemsintheangleofinteroperability,butbecausesystemshavetoevolveandinteroperateinmanynewwayswhichwerenotforeseenearlier.Thispushesintegrationproviderstodefinenewsoftwarepipesacrossapplications.Whenwestartthisactivityitmightbeelegantandstraightforward,butsoonerthanlaterwerealizethatourintegrationpipeshavenocentralcontrol,administration,ormanagementprovisions.
IntegrationArchitecturesThefirstandforemoststepinunderstandingintegrationarchitecturesistounderstandthedifferenttopologiesexistinginintegrationarena,andtoappreciatethevitaldifferencebetweenthem.Ifonecanunderstandthetruedifference,halfthejobisalreadydone.Understandingthedifferencewillenabletheintegrationarchitecttoattachprescriptivearchitectureforagivenintegrationproblem.Letusnowunderstandthebasicintegrationarchitecturesthatarelistedasfollows:
Point-to-Pointsolution
Hub-and-Spokesolution
EnterpriseMessageBusIntegration
EnterpriseServiceBusIntegration
Point-to-PointSolutionEAIhastraditionallybeendoneusingpoint-to-pointintegrationsolutions.Inpoint-to-point,wedefineanintegrationsolutionforapairofapplications.Thuswehavetwoendpointstobeintegrated.Wecanbuildprotocoland/orformatadapters,ortransformersatoneoreitherend.Thisistheeasiestwaytointegrate,aslongasthevolumeofintegrationislow.Wenormallyusetechnology-specificAPIslikeFTP,IIOP,remotingorbatchinterfaces,torealizeintegration.Theadvantageisthatbetweenthesetwopoints,wehavetightcoupling,sincebothendshaveknowledgeabouttheirpeers.
Thefollowingfigureisthediagrammaticrepresentationofthepoint-to-pointintegration:
Hub-and-SpokeSolutionHub-and-spokearchitectureisalsocalledthemessagebrokerandissimilartopoint-to-pointarchitectureinthatitprovidesacentralizedhub(broker)towhichallapplicationsareconnected.Whenmultipleapplicationsconnectinthismanner,wegetthetypicalhub-and-spokearchitecture.Anotherdistinguishingfeatureofthehub-and-spokearchitectureisthateachapplicationconnectswiththecentralhubthroughlightweightconnectors.Thelightweightconnectorsfacilitatesforapplicationintegrationwithminimumornochangestotheexistingapplications.Messagetransformationandroutingtakesplacewithinthehub.Thisarchitectureisamajor
improvementtothepoint-to-pointsolutionsinceitreducesthenumberofconnectionsrequiredforintegration.Sinceapplicationsdonotconnecttootherapplicationsdirectly,theycanberemovedfromtheintegrationtopologybyremovingfromthehub.Thisinsulationreducesdisruptionintheintegrationsetup.
Thereisamajordrawbackwiththehub-and-spokearchitecture.Duetothecentralizednatureofthehub,itisasinglepointoffailure.Ifthehubfails,theentireintegrationtopologyfails.Asolutiontothisproblemistoclusterthehub.Aclusterisalogicalgroupingofmultipleinstancesrunningsimultaneouslyandworkingtogether.Butclusteringisnottherightsolutiontotheproblemofsinglepointoffailure.Thisisduetothefactthattheverypointinhavingahub-and-spokearchitectureistohaveasinglepointofcontrol.Thisdrawbackmaybeoffsettosomeextentbythefactthatmostoftheclusteringsolutionsprovidecentralmanagementandmonitoringfacilities,whichwillprovidesomeformofcentralizedcontrol.
Thefollowingfigureisthediagrammaticrepresentationofthehub-and-spokeintegration:
EnterpriseMessageBusIntegrationWhilethehub-and-spokearchitecturemakesuseoflightweightconnectorsforapplicationstointegratetogetherthroughacentralhub,manyatimestheintegratingapplicationsneedtointeractinadecoupledfashion,sothattheycanbeeasilyaddedorremovedwithoutaffectingtheothers.Anenterprisemessagebusprovidesacommoncommunicationinfrastructure,whichactsasaplatform-neutralandlanguage-neutraladapterbetweenapplications.
Thiscommunicationinfrastructuremayincludeamessagerouterand/orPublish-Subscribechannels.Soapplications
interactwitheachotherthroughthemessagebuswiththehelpofrequest-responsequeues.Ifaconsumerapplicationwantstoinvokeaparticularserviceonadifferentproviderapplication,itplacesanappropriatelyformattedrequestmessageontherequestqueueforthatservice.Itthenlistensfortheresponsemessageontheservice'sreplyqueue.Theproviderapplicationlistensforrequestsontheservice'srequestqueue,performstheservice,andthensends(if)anyresponsetotheservice'sreplyqueue.
WenormallyusevendorproductslikeIBM'sWebsphereMQ(WMQ)andMicrosoftMQ(MSMQ),whicharethebestclassmessagequeuesolutiontointegrateapplicationsinthemessagebustopology.Asshowninthefollowingfigure,sometimestheapplicationshavetouseadapterwhichhandlescenariossuchasinvokingCICStransactions.SuchanadaptermayprovideconnectivitybetweentheapplicationsandthemessagebususingproprietarybusAPIs,andapplicationAPIs.TheMessagebusalsorequiresacommoncommandstructurerepresentingthedifferentpossibleoperationsonthebus.Thesecommandsetsinvokebus-levelprimitiveswhichincludeslisteningtoanaddress,readingbytesfromanaddress,andwritingbytestoanaddress.
EnterpriseServiceBusIntegrationTheservicebusapproachtointegrationmakesuseoftechnologystackstoprovideabusforapplicationintegration.Differentapplicationswillnotcommunicatedirectlywitheachotherforintegration;insteadtheycommunicatethroughthismiddlewareServiceOrientedArchitecture(SOA)backbone.ThemostdistinguishingfeatureoftheESBarchitectureisthedistributednatureoftheintegrationtopology.MostESBsolutionsarebasedonWebServicesDescriptionLanguage(WSDL)technologies,andtheyuseExtensibleMarkupLanguage(XML)formatsformessagetranslationandtransformation.
ESBisacollectionofmiddlewareserviceswhichprovidesintegrationcapabilities.ThesemiddlewareservicessitintheheartoftheESBarchitectureuponwhichapplicationsplacemessagestoberoutedandtransformed.Similartothehub-and-spokearchitecture,inESBarchitecturetoo,applicationsconnecttotheESBthroughabstract,intelligentconnectors.Connectorsareabstractinthesensethattheyonlydefinethe
transportbindingprotocolsandserviceinterface,nottherealimplementationdetails.Theyareintelligentbecausetheyhavelogicbuilt-inalongwiththeESBtoselectivelybindtoservicesatruntime.Thiscapabilityenhancesagilityforapplicationsbyallowinglatebindingofservicesanddeferredservicechoice.
ThefollowingfigureisthediagrammaticrepresentationofESBintegration:
TheabovequalitiesofESBprovidesforatrueopenenterpriseapproach.Aswehavediscussedabove,ESBisneitheraproductnoraseparatetechnology;instead,ESBisaplatform-levelconcept,asetoftools,andadesignphilosophy.What
thismeansis,ifwejustbuyavendorproductandinstallitinourITinfrastructure,wecannotsaythatwehaveESB-basedintegrationarchitecture.InsteadESB-basedintegrationsolutionsaretobedesignedandbuiltinthe"ESBway".Toolsandproductshelpustodothis.
AlistofmajorfeaturesandfunctionalitiessupportedbyanESBwillhelpustounderstandthearchitecturebetter,whicharelistedasfollows:
Addressingandrouting
Synchronousandasynchronousstyle
Multipletransportandprotocolbindings
Contenttransformationandtranslation
Businessprocessorchestration
Eventprocessing
Adapterstomultipleplatforms
Integrationofdesign,implementation,anddeploymenttools
QOSfeaturesliketransactions,security,andpersistence
Auditing,logging,andmetering
Managementandmonitoring
EnterpriseServiceBusversusMessageBusLet'sleavealonethepoint-to-pointandthehub-and-spokearchitectures,sinceitisrathereasytounderstandthemandyouhavebeendoingtheminonewayoranother.Butwhen
wediscussaboutESBandmessagebus,weneedtounderstandthesimilaritiesanddifferencesbetweenthesetwotopologies.
SimilaritiesandDifferencesLetusfirstseehowthemessagebusandtheservicebusarealike.Infact,bothofthemareaimedtosolvetheproblemofintegrationandprovideacommoncommunicationinfrastructure,whichactsasaplatform-neutralandlanguage-neutraladapterbetweenapplications.Somediationistheprimefunctionalityprovidedbyboththearchitectures.Applicationscanintegrateeachotherinalooselycoupledmannerthroughthismediator,sothattheywillnotbedependentoneachother'sinterfaces.Lastbutnottheleast,usingeitherthemessagebusortheservicebusarchitecture,youcanimplementSOA-basedintegrationsolutions!
Thelaststatementmightbehardtodigest—atleastsomeofyoumighthavethoughtthatoneispurelySOA-basedwhiletheotherisnot.ButthefactisthatboththemessagebusandtheservicebushelpsenterprisestoattainanSOAecosystem,ifarchitectedproperly,butneitherofthembyitselfwillautomaticallytransferexistingnon-SOAarchitectureintoSOA-basedarchitecture.
Now,whatisthedifferencebetweenamessagebusandaservicebus?
Beforewedigintothedifferencesletmegiveyouawordof
caution.Eventhoughthemaindifferencesbetweenamessagebusandaservicebuswillbelistedasfollows,theymaynotbeveryobviousinthefirstread.Hence,Irecommendthereadertogothroughthesubsequentchaptersandsamplestoo,andgetafeelofhowwedothingsinthe"ESBway",andthenrevisitthegivendifferences.
NOTENOTE
Themaindifferencebetweenenterprisemessagebusandenterpriseservicebusarchitectureisinthemannerinwhichtheconsumerortheclientapplicationinteractwiththemessagingmiddleware.
Moreeasilysaid,thanunderstood!OK,letusworryless(Ididn'tsay"letusworrynot"!),understandmore.
ServicedescriptionandservicediscoveryaretwokeyelementstoattainhigherlevelsofSOAmaturity.Onlyifsomethingisdescribed,canitbediscovered.Thisiswhereaserviceregistryisgoingtoaddvalue,thereyoucanregisteraservicedescriptionsothatsomeotherinterestedpartycandiscoverit.
Letusnowcomebacktoourmessagebus.Weearliersawthatmessagebusapplicationsinteractwitheachotherwiththehelpofrequest-responsequeues.Ifyouhaveeverworkedinanymessagingsolution(likeJMS)before,thenyouwillappreciatethefactthatqueuesareaddressedbythemselves,whichwillnotgiveyouanyfurtherinformationabouttheunderlyingservice.Informationontheoperationsavailable,orthemessagingpatternstoexpect,ortheschemaforthetypesexchangedisneveravailableatthequeue-level.Inother
words,servicesarenotdescribedinamessagebus.
Whatisavailableisjustthemessagingcounterpartsfortheputandgetprimitivessothatmessagescanbesenttoandreceivedfromthemessagebus.Soconsumerorclientapplicationsshouldhavepre-awarenessoftheformatofthemessagesexchanged.Thisimplieseverythinghastobeknownbeforehand—rather,staticbindingorcompile-timebindingbecomesthenorm.
Letusnowconsidertheservicebus.WesaidearlierthatmanyESBsolutionsarebasedonWSDLtechnologies,andtheyuseXMLformatsformessagetranslationandtransformation.Thisbyitselfgivesuslotofopportunitiesforservicedescriptionanddiscovery.Allthe(minimum)detailsabouttheservicewillbeavailablefromtheWSDL.Hence,messageexchangepatternsandmessageformatsarereadilyavailable.Moreover,theconsumerorclientapplicationscandiscoveramatchingservicefromtheESB,givenasetofmessagingcapabilities(WSDLcapabilities)theyarelookingfor.IusedthetermmatchingservicebecauseinanidealESBarchitecturetheconsumerislookingforcapabilitieswhichmatchtheirabstractserviceexpectations(interface).ItistheroleoftheESBtoroutetherequeststoanyconcreteserviceimplementationbehindthebuswhichmatchestherequestedinterface.
Thenextbigdifferenceisthetypeofapproachusedineacharchitecture.Inservicebusarchitectureweusedastandard-basedapproach.WhenservicesareWSDL-based,itbringsatimetestedandwelladoptedindustrystandardtointegration.ThishasabigpayoffwhencomparedtotraditionalMessage
OrientedMiddleware(MOM),becauseinthemessagebusarchitecturetheadaptersprovideconnectivityusingproprietarybusAPIsandapplicationAPIs.So,whereasinthepre-ESBworld,wehavebeenusingCORBAIDL(InterfaceDefinitionLanguage),orTuxedoFML(FieldManipulationLanguage),orCOM/DCOMMicrosoftIDL,andCICScommonArea(COMMAREA)astheservicedefinitionlanguage,wenowuseWSDLastheinterfaceinstandard-basedESBarchitectures.
MaturityandIndustryAdoptionHavinglookedatafewofthesimilaritiesanddifferencesbetweenservicebusandmessagebus,itistimenowtolookatrealitieswhichexistintheindustrytoday.WeagreedthatanESBcandolotmanythings,andforthatmatteramessagebuscantoo.Wethentalkedaboutthedifferencesaservicebushastooffer.
Howmatureisthetechnologytodaytoaddressthesedifferences?Havewestartedpracticalimplementationsofservicebusinabigwayyet?Theanswertothisquestionisneitheryesnorno.Thereasonisthatnecessityrunsbeforestandards.Rather,whenyouagreethatyouneeddescriptionanddiscoveryalongwithotherfeaturesforaservicebus-basedarchitectures,thequestionis,willtheexistingstandardslikeUniversalDescriptionDiscoveryandIntegration(UDDI)alonewillhelptoachievethis?Maybeweneedasimpleandstandardwaytospecifyapairofrequest-replyqueuesalongwithaHTTPURL(mechanismtospecifyHTTPURLis
alreadyavailable)intheWSDLitself.Thiswayaconsumerorclientapplicationcaninteractinthe'MOMway'throughtheESB.Maybewealsoneedasimpleand,again,astandardwaytofindandinvokeaconcreteserviceattheESB,matchinganabstractserviceinterface.
Thesestandardsareevolvingandareatdifferentstagesofadoption.Similaristhecaseofsupportforthesecapabilitiesacrossmultiplevendors'solutions.Hence,thetailpieceisthatitistimenowtogatherallourexperienceinmessagebusbasedarchitectures,andleverageittodefineanddemonstrateservicebus-basedarchitecture.So,howdowedecidethatweneedanESB-basedArchitecture?Readonthenextsectionandyouwillcometoknow.
MakingtheBusinessCaseforESBJustlikeanyoneofyou,IamnotsatisfiedyetwithenoughreasonsforwhytouseESB.Hence,thissectionisgoingtoexplainmoreaboutthevaluepropositionESBisgoingtobringtoyourITinfrastructure.
Thereareafewconcernsweneedtoaddresswhenwedopoint-to-pointorasimilarstyleofintegration:
Howmanychannelsdoweneedtodefineforcompleteinteroperability?
Howeasyitistochangeasysteminterface,whilestillmaintaininginteroperability?
HowdoweaccommodateanewsystemtotheITportfolio?
Howmuchwecanreusesystemservicesinthistopology?
Wheredoweplug-insystemmanagementormonitoringfunctionality?
Letusaddresstheseissuesonebyone.
HowmanyChannelsLetusgobacktothepoint-to-pointintegrationscenarioandassumethatwehavefourseparatein-housesystems,oneforeachofthefourseparatedepartments(HR,Accounts,R&D,andSales).Theoperationalproblemthebusinessfacesistointeroperatethesesystems.Inthepoint-to-pointintegration,weneedtohaveindependentchannelsofconnectionbetweeneachpairofsystems.Thesechannelsarestatic,stronglytyped,andwithoutmuchintelligencefordynamicroutingortransformation.Theadvantageisthatitisrathereasytobuildthesolution.
Asshowninthenextfigure,iftherearesixsystems(nodes)tobeinterconnected,weneedatleastthirtyseparatechannelsforbothforwardandreversetransport.IfweaddonemorenodetotheITportfolio,thenumberofchannelstobedefinedgoesupfromthirtytofortytwo.Thismeans,astimepassesandasmoreandmoresystemsandapplicationsareaddedtotheorganization,thenumberofinterconnectionsorchannelstobedefinedbetweenthesesystemsrisesexponentially,intheorderoftwo.
Wecangeneralizethenumberofchannels(Nc)requiredfor
completeinterconnectionfornseparatesystemsas:
Nc=n -n
Thisnumberisstillmanageableforsmallorganizationswithasmallnumberofsystems,butexperiencehasshownthatthisisgoingtobeanightmareformid-sizedandlarge-sizedorganizations.Itiscustomaryforsuchorganizationstohavemorethanfiftyorhundredsystems.Forcompleteinteroperabilityinahundredsystemscenario,weneedtodefinearoundtenthousandseparatechannels!Leavealonethedefinition,howdowemaintainsuchahugenetworkofinterconnection?
2
Perhaps,everysysteminanorganizationneedn'tinteroperatewitheveryothersystem.Again,experiencehasshownthatonlyhalfofthemneedtointeroperatefully,thusbringingdownthefiguretofivethousand.Whatthismeansis,wehavetobuildfivethousandadapterstodefinechannelstointeroperateforthesesystems.Stillthisnumberisnotmanageable.
VolatileInterfacesInaperfectworld,wecansomehowbuildfivethousandseparateadapterstointerconnectahundredsystemsbyfiftypercent,andthenhopetorelax.Buttherealscenarioisfarfromperfect.Theimperfectionarisesoutofconstantinnovationandevolution,andthisforceschangeeventosysteminterfaces.AnintdatatypeinC++isoftwobyteswhereasthesameintinJavaisoffourbytes.Wehavealreadytakencareofthisdataimpedancebybuildingadapters.But,whatifononefinemorning,theC++applicationstartsspittingfloatinsteadofint?Theexistingadapterisgoingtofail,andweneedtoreworkontheadapterinthischannel.
Thegoodnewsis,withinanorganizationthiscanbecontrolledandmanagedsincewehaveaccesstoboththeendsoftheadapter.ThescenarioworsenswhentheinterfacechangesinaB2Bscenariowheresystemsbetweentwoseparateorganizationsinteract.Asweknowalready,thisisgoingtohappen.So,wehavetobuildagileinterfaces.
NewSystemsIntroducingDataRedundancyAddingnewsystemsisanaftereffectofbusinessexpansion,buttherearemultiplerisksassociatedwithit.First,weneedtointegratenewsystemswiththeexistingsystems.Secondly,manyatime,newsystemsintroducedataredundancy.Thisisbecausethesamedatamightgetenteredintothenetworkthroughmultipleinterfaces.Similaristheproblemofthesamedataduplicatedatdifferentpartsoftheorganization.ThiscontradictstherequirementsofStraight-ThroughProcessing(STP).STPaimstoentertransactionaldataonlyonceintothesystem.Thisdatacanflowwithinoroutsidetheorganization.ToachieveSTP,thereshouldbemechanismforseamlessdataflow,alsoinaflexiblemanner.
DataredundancycanbemanagedifandonlyifthereisamechanismtoconsolidatedataintheformofCommonInformationModel(CIM).Forexample,theNGOSS'sSharedInformation/Data(SID)modelfromTelecomManagementForumistheindustry'sonlytruestandardfordevelopmentanddeploymentofeasytointegrate,flexible,easytomanageOSS/BSScomponents.TheSIDprovidesaninformationordatareferencemodelandacommoninformationordatavocabularyfromabusinessandsystemsperspective.Noteverydomainororganizationhasaccesstoareadymadeinformationmodelsimilartothis.
Insuchascenario,ESBcanplayavitalrolebyprovidingtheedgeofthesystemviewbywrappingandexposingavailablenetworkresources.Thus,ESBprovideshooksfora"leave-
and-layer"architecturewhichmeansthatinsteadofalteringexistingsystemstoprovideastandards-basedservicesinterfacetheyarewrappedwithalayerthatprovidestheservicesinterface.
ServiceReuseCodeandcomponentreuseisafamiliarconceptamongstdesignersanddevelopers.WehaveGangofFourpatternstoprescribedesignsolutionsforrecurringproblems.ButwiththeinventionofSOA,wehavewhatiscalledtheServiceOrientedIntegration(SOI)whichmakesuseofEnterpriseIntegrationPatterns(EIP).SOIspeaksaboutthebestwaysofintegratingservicessothatservicesarenotonlyinteroperablebutalsoreusableintheformofaggregatinginmultiplewaysandscenarios.Thismeans,servicescanbemixedandmatchedtoadapttomultipleprotocolsandconsumerrequirements.
Incodeandcomponentreuse,wetrytoreducecopyandpastereuseandencourageinheritance,composition,andinstancepooling.AsimilaranalogyexistsinSOIwhereservicesarehostedandpooledformultipleclientsthroughmultipletransportchannels.ESBdoesexactlythisjobinthebestwayintegrationworldhaseverseen.Forexample,ifafinancialorganizationprovidesacredithistorycheckservice,anESBcanfacilitatereuseofthisservicebymultiplebusinessprocesseslikeaPersonalLoanapprovalprocessoraHomeMortgageapprovalprocess.
SystemManagementandMonitoringCrosscuttingconcernsliketransactionsorsecurityorevenServiceLevelAgreement(SLA)managementandmonitoringarejustafewofasetoffeaturesapartfrombusinessfunctionalitythatanyenterpriseclassserviceecosystemhastoprovide.TheESBarchitecturesprovidesenoughhookstoattachsimilarservicesontothebusseparatefromnormalbusinessfunctionality.Thisensuresthatthesecrosscuttingfunctionalitycanbeappliedtoallservicesandalsoenableustomanage,monitor,andcontrolthemcentrally.
EnterpriseServiceBusHavingunderstoodthevariousintegrationproblems,whichcanbeaddressedinmultipleways,ofwhichESBisoftheprimeconcernandiscentraltoourdiscussioninthisbook,wewilltrytounderstandtheESBbetterhere.
ServiceinESBItistimenowtounderstand"Service"inESB.Whydon'twecallitEnterpriseComponentBus?
Servicesareexposedfunctionalitieswhichareclearlydefined,selfcontained,andwhichwillnotdependonthestateandcontextofpeerservices.Asshowninthefollowingfigure,theservicehasaservicedescription(similartoWSDL)anditis
thisdescriptionwhichisexposed.Itisnevernecessarytoexposetheimplementationdetails,andinfact,weshouldn'texposethem.Itisthishiddennatureoftheimplementationwhichhelpsustoreplaceserviceswithsimilarservices.Thus,serviceprovidersexposetheservicedescriptionandserviceconsumersfindthem.
Oncetheservicedescriptionisfoundserviceconsumerscanbindtoit.Moreover,itisduringthetimeofactualbinding,weneedmoreinformationliketransportprotocols.Asweknow,wecanhandlewithtransportdetailswiththehelpofprotocoladapters.Intelligentadaptersarerequiredifweneedtoroutemessagesbasedoncontentorcontext.Theseadaptersareofadifferentkindlikesplittersandcontentbasedrouters.ESBisallaboutaruntimeplatformforthesekindsofadaptersandrouters,whicharespecificallydesignedforhostingandexposingservices.
AbstractionbeyondInterfaceAlmostallOOPlanguagessupportinterface-driven
developmentandhencethisisnotanewconcept.SeparatinginterfacefromimplementationabstractstheServiceConsumerfromtheimplementationdetailsfromaServiceProviderperspective.But,whataboutabstractingoutthisinterfaceitself?IftheServiceConsumerinteractsdirectlywiththeServiceProvider,boththesepartiesaretightlycoupledanditmaybedifficulttochangetheinterface.Instead,aservicebuscaneffectivelyattachitselftoaserviceregistry.Thismeans,aconsumercanevenbeunawareoftheserviceinterface.
Now,justintime,theconsumercanselectivelychooseanappropriateinterfacefromaregistry,thenbindtoasuitableimplementationthroughanESB,andinvoketheserviceatruntime.Suchkindsofflexibilitycomeatthecostofdesigntimeorcompiletimetypechecking,whichcanbeerrorproneduringserviceinvocationusingconventionaltools.AnESBwithitssetoftoolsanddesignprimitiveshelpsdeveloperstoeffectivelyaddressthis.
ServiceAggregationThekeyvalueofaggregation,here,isnotsomuchinbeingabletoprovidecoreservices,whichdevelopershavetobuildanyway.Itistofacilitateanarbitrarycompositionoftheseservicesinadeclarativefashion,soastodefineandpublishmoreandmorecompositeservices.BusinessProcessManagement(BPM)toolscanbeintegratedoverESBtoleverageserviceaggregationandservicecollaboration.Thisfacilitatereuseofbasicorcore(orfinegrained)servicesatthebusinessprocess-level.So,granularityofservicesisimportant
whichwillalsodecidethelevelofreusability.
CoarseGrainedorCompositeServicesconsumeFineGrainedServices.ApplicationswhichconsumeCoarseGrainedServicesarenotexposedtotheFineGrainedServicesthattheyuse.CompositeServicescanbeassembledfromCoarseGrainedaswellasFineGrainedServices.
Tomaketheconceptclear,letustaketheexampleofprovisioninganewVOIPServiceforanewcustomer.ThisisaCompositeServicewhichinturncallsmultipleCoarseGrainedServicessuchasvalidateOrder,createOrVerifyCustomer,andcheckProductAvailability.Now,createOrVerifyCustomer,theCoarseGrainedServiceinturncallmultipleFineGrainedServiceslikevalidateCustomer,createCustomer,createBillingAddress,andcreateMailingAddress.
Asisshownintheabovefigure,aCompositeServicesisanaggregateofotherCompositeServicesand/orCoarseGrainedServices.Similarly,CoarseGrainedServicesareagainaggregatesofotherFineGrainedServices.Whereas,FineGrainedServicesimplementminimumfunctionalityandarenotaggregatesofotherservices.ESBhereactsasasharedmessaginglayerforconnectingapplicationsandotherservicesthroughouttheenterprise,thusprovidingaworkbenchfor
serviceaggregationandcomposition.
ServiceEnablementServicescanbedesignedbutifleftalonetheywillsitidle.TheideabehindtrueSOAisnotjustservicedefinitionorimplementation,butalsoserviceenablement.Byserviceenablement,wemeanenabling,configuring,tuning,andattachingQOSattributestoservices,sothattheyareaccessible,asperSLAirrespectiveofformatsortransportprotocols.
Usingtoday'stechniqueslikeAspectOrientedProgramming(AOP),Annotationsandbytecodeinstrumentation,serviceenablementcanbedonewithoutanydependencyontheservicesframework.AnESBdoesexactlythis.ItistobenotedthataJBI-basedESBwilldothisAPI-less.ItisnotcompletelyAPI-less,inthesensethatthereisalwaysadependencyonanXMLconfigurationorannotation.Thedifferentiatingfactoristhatthisdependencyisexternalizedsothattheyarenotcementedtotheserviceimplementation.
ServiceConsolidationServiceconsolidationisanimportantsteptoeliminateredundantinformationanddata.Asapartofserviceconsolidation,wemayhavetofirstconsolidateITinfrastructureanddataassetsinthenetwork.Thereshouldbeclearownershipforthesetwoentities,sothatweknowwhoorwhichapplicationsarechangingwhichsectorsofthedata
assets.Oncethisisdone,thenextstepistodoapplicationportfolioanalysisanddodirectmappingbetweenservicesanddataoperations(business-levelCRUD).
ApointtobenotedhereisthatIamnottalkingaboutexposingsimpleCreate,Read,Update,andDeleteoperationstobeexposedasservices,sincetheyarenot(coarsegrained)servicesatall.Theyarejustfunctionstoaltertheconstantsofdatamodelandifweexposethemasservices,wearetryingtoexposeourinternaldatamodeling,whichisgoingtoimpactinternalagility.Instead,whatwehavetoexposeisourcoarsegrainedbusinessoperations(processes)whichcarryoutusefulbusinessfunctionsonbehalfofclientapplications.Whenwedothat,wecanmapwhichservicesneedtobeinvokedtofinishanonlineretailingexperience,andwhichotherservicesareresponsibleforrealizingtheretailbookinginthebackofficesystems.
Thusservicesarenamed,labeled,andallthemoreindexed.Andyoulookattheindexforaparticularservicesimilartothewayyoulookatabookindex,tofindaparticularsubject.Thus,weeffectivelypoolservicesandconsolidateunusedcapacityformerlyspreadovermanyconnectedsystemsandservers.
ServiceSharingMessagebusfacilitatesservicesharingascomparedtoservicereuse.InfactservicesharingisoneofthekeyaspectsofSOA.
Inservicereuse,thesameserviceishostedindifferentdeploymentenvironmentsduetovariousreasons.Eventhoughthecomponentorthecodebehindtheserviceisreusedhere,thereissignificantoverheadintermsofdeployment,management,andmaintenance.TheServicereusescenarioisasshowninthefollowingfigure:
Servicesharingis,incontrast,thetruesharingofaserviceitself.Thismeanstheservicehostingenvironmentisconfiguredfordifferentscenariosandconsumersaccessthesameserviceinstancethroughmultiplechannelsorformats.SOAwebservicescanbeleveragedtoachievethis,andthisisfurtherenabledusingamessagebusasshowninthefollowingfigure:
LinkedServicesMicrosoftSQLServerhastheabilitytoqueryremotedatabaseobjectsasiftheywerelocaltotheserver.Linkedserversareusefulindeployments,wherethedatacanbesplitbyfunctionalareaintodatabaseswithverylittlecouplingasameansofscaleoutstrategy.Thismeansthatascaledoutdatabasecanlooklikeasinglelargedatabasetoanapplication.Similartothis,ESBcanbeseenasameanstolinkservices.Bindingtoremoteendpointsissynonymoustolinkingtoremotedatabases—anapplicationcodecaninteractwiththelinkedservicesasiftheywerelocaltotheinvokingcode.
VirtualizationofServicesByservicevirtualization,Imeandividingtheorganization'sinformationassetsinto"VirtualServices"withoutregardtothetransportorbindingprotocoloftheactualimplementationcomponents.Corporatenetworkassets(information)canresideinmultipleplaceslikeinacentralizedmainframeordistributedacrossmultiplesystemsimplementedusingDCOM,RMI,IIOP,remoting,orSOAPprotocols.
Servicewrappingandserviceaggregationaretwomethodsbywhichwecanvirtualizethemtobeexposedinaconsistentwaytoexternalorinternalclients.Thus,virtualizationiscloselyrelatedto"blackbox"reuseofservicesbyprovidingadifferentinterfaceatthesameabstraction-level.TheESBabstractsbehindthesceneaddressing,translations,andaggregation.
Well-definedinterfacesfacilitatedevelopmentofinteractingsoftwaresystemsnotonlyindifferentLOBs,butalsoatdifferenttimes,thusprovidingasuitableabstractionforanyconsumersoftheservice.Butabstractionhasanegativesidetoo—softwaresystems,components,orservicesdesignedforoneinterfacewillnotworkwiththosedesignedforanotherinterface.This,infact,isaninteroperabilityissuewhichcanbeaconcern,especiallyinaworldofnetworkedcomputerswherethetrendistomovedataandinformationfreely.
Servicevirtualizationisawaytocircumventthisissuebymappingthevisibleinterfaceofaserviceontotheinterfaceandresourceofanunderlying,possiblydifferent,realservice.
ThisfiguredepictstheconceptofServiceVirtualization,wherewemakeuseofcoreESBfeatureslikeAggregation,Routing,andTranslationtorepublishtheexistingserviceassets.Theseareexplainedindetailinsubsequentchapters.
ServicesFabricWe,integrationpeople,needtolearnlessonsfromthewaynetworkarchitectsorganizetheirnetworkchannels.Whenusingfiber,networkarchitectshavethreenetworktopologies.Forthefibrechanneloption,wehavethreenetworktopologiesviaanyfromthefollowinglist:
Point-to-point
Arbitratedloop
Fabric
Inthefabrictopology,thereareoneormorehardwareswitchesinadditiontoportsoneachdevicetonetwork.Comparatively,inESBwehaveintelligentadapters.MultipleclientscanhittheESBfabric,andintelligentadaptersattheESBedgeareresponsiblefordynamicbindingofclient
requeststoappropriateconcreteserviceimplementations.Thus,ESBservicesfabricfunctionsasthevirtualizationlayer.Inotherwords,theESBprovidesinfrastructurecapabilitiesandapplicationplug-inpointsforanSOAfabricforthewholeenterprise.
SummaryInformationintegrationisasoldasInformationTechnology(IT)itself.Wehavebeendoingitinmultiplewaysandusingmultipletechnologystacks.But,whatismoreimportantisthat,attheendoftheday,theintegratedsolutionshouldbesolvingmoreexistingproblemsandintroducinglessnewproblems.ThisiswhereselectingandchoosingappropriateintegrationarchitectureismostimportantintheITlandscape.
WehaveseenwhatESBarchitectureisandhowitisdifferentfromotherpeerintegrationarchitectures.Sofarsogood,andtoday,youcanreadanynumberofdocumentsonESBfromtheInternet.We,asarchitectsanddevelopersnow,alsoneedtoimplementtheminourcode,notjustinsketchesinwhitepapersandpresentations.HowcanwedothatusingJava?
Inthenextchapter(JavaBusinessIntegration),wewillseeexactlywhatJavahastoofferindefiningESBarchitectures.
Chapter2.JavaBusinessIntegrationIntegrationhasbeenanareaforspecialistsforyears,sincenostandardsexistacrossvendorproducts.ThisincreasestheTotalCostofOwnership(TCO)toimplementandmaintainanyintegrationsolution.Eventhoughintegrationisanecessaryevil,CIOsandITmanagerspostponedecisionsandactions,andsometimesgoforad-hocortemporarysolutions.Anysuchactivitywillcomplicatethealreadyconfusedstovepipesanditistheneedofthehourtohavestandardization.Herewearegoingtoinspecttheneedofanotherstandardforbusinessintegration,andalsolookintothedetailsofwhatthisstandardisallabout.
Sowewillcoverthefollowinginthischapter:
Serviceorientedarchitectureinthecontextofintegration
RelationshipbetweenwebservicesandSOA
Serviceorientedintegration
J2EE,JCA,andJBI—howtheyrelate
IntroductiontoJBI
JBINomenclature—maincomponentsinJBI
Provider-consumerrolesinJBI
JBIMessageExchangePatterns(MEP)
SOA—TheMottoInChapter1,wewentthroughintegrationandalsovisitedthemajorintegrationarchitectures.Wehavebeendoingintegrationformanydecadesinproprietaryorad-hocmanner.Today,thebuzzwordisSOAandintheintegrationspace,wearetalkingaboutServiceOrientedIntegration(SOI).LetuslookintotheessentialsofSOAandseewhethertheexistingstandardsandAPIsaresufficientintheintegrationspace.
WhyWeNeedSOAWehavebeenusingmultipletechnologiesfordevelopingapplicationcomponents,andafewofthemarelistedasfollows:
RemoteProcedureCall(RPC)
CommonObjectRequestBrokerArchitecture(CORBA)
DistributedComponentObjectModel(DCOM)
.NETremoting
EnterpriseJavaBeans(EJBs)
JavaRemoteMethodInvocation(RMI)
Onedrawback,whichcanbeseeninalmostallthesetechnologies,istheirinabilitytointeroperate.Inotherwords,ifa.NETremotingcomponenthastosendbytestoaJavaRMIcomponent,thereareworkaroundsthatmaynotworkallthetimes.
Next,alltheabovelistedtechnologiesfollowthebestObjectOrientedPrinciples(OOP),especiallyhidingtheimplementationdetailsbehindinterfaces.Thiswillprovideloosecouplingbetweentheproviderandtheconsumer,whichisveryimportantespeciallyindistributedcomputingenvironments.Nowthequestionis,aretheseinterfacesabstractenough?Torephrasethequestion,canaJavaRMIruntimemakesenseoutofa.NETinterface?
Alongtheselines,wecanpointoutafulllistofdoubtsordeficiencieswhichexistintoday'scomputingenvironment.ThisiswhereSOAbringsnewpromises.
WhatisSOASOAisallaboutasetofarchitecturalpatterns,principles,andbestpracticestoimplementsoftwarecomponentsinsuchawaythatweovercomemuchofthedeficienciesidentifiedintraditionalprogrammingparadigms.SOAspeaksaboutservicesimplementedbasedonabstractinterfaceswhereonlytheabstractinterfaceisexposedtotheoutsideworld.Hencetheconsumersareunawareofanyimplementationdetails.Moreover,theabstractmodelisneutralofanyplatformortechnology.Thismeans,componentsorservicesimplementedinanyplatformortechnologycaninteroperate.WewilllistoutfewmorefeaturesofSOAhere:
Standards-based(WS-*Specifications)
Servicesareautonomousandcoarsegrained
Providersandconsumersarelooselycoupled
Thelistisnotexhaustive,butwehavemanynumberofliteratureavailablespeakingonSOA,soletusnotrepeatithere.InsteadwewillseetheimportanceofSOAintheintegrationcontext.
SOAandWebServicesSOAdoesn'tmandateanyspecificplatform,technology,orevenaspecificmethodofsoftwareengineering,buttimehasproventhatwebserviceisaviabletechnologytoimplementSOA.However,weneedtobecautiousinthatusingwebservicesdoesn'tleadtoSOAbyitself,orimplementit.Rather,sincewebservicesarebasedonindustryacceptedstandardslikeWSDL,SOAP,andXML;itisoneofthebestavailablemeanstoattainSOA.
ProvidersandconsumersagreetoacommoninterfacecalledWebServicesDescriptionLanguage(WSDL)inSOAusingwebservices.DataisexchangednormallythroughHTTPprotocol,inSimpleObjectAccessProtocol(SOAP)format.
WSDLWSDListhelanguageofwebservices,usedtospecifytheservicecontracttobeagreeduponbytheproviderandconsumer.ItisaXMLformattedinformation,mainlyintendedtobemachineprocessable(buthumanreadabletoo,sinceitisXML).Whenwehostawebservice,itisnormaltoretrievetheWSDLfromthewebserviceendpoint.Also,therearemainlytwoapproachesinworkingwithWSDL,whichare
listedasfollows:
StartfromWSDL,createandhostthewebserviceandopentheserviceforclients;toolslikewsdl2javahelpustodothis.
Startfromthetypesalreadyavailable,generatetheWSDLandthencontinue;toolslikejava2wsdlhelpushere.
LetusnowquicklyrunthroughthemainsectionswithinaWSDL.AWSDLstructureisasshownhere:
<?xmlversion="1.0"encoding="UTF-8"?>
<wsdl:definitionstargetNamespace=
"http://versionXYZ.ws.servicemix.esb.binildas.com"
…>
<wsdl:types>
<schemaelementFormDefault="qualified"
targetNamespace="http://version20061231.ws.
servicemix.esb.binildas.com"
xmlns="http://www.w3.org/2001/XMLSchema">
</schema>
</wsdl:types>
<wsdl:messagename="helloResponse">
<!--othercodegoeshere-->
</wsdl:message>
<wsdl:portTypename="IHelloWeb">
<!--othercodegoeshere-->
</wsdl:portType>
<wsdl:binding
name="HelloWebService20061231SoapBinding"
type="impl:IHelloWeb">
<!--othercodegoeshere-->
</wsdl:binding>
<wsdl:servicename="IHelloWebService">
<wsdl:port
binding="impl:HelloWebService20061231SoapBinding"
name="HelloWebService20061231">
<wsdlsoap:address
location="http://localhost:8080/AxisEndToEnd20061231/
services/HelloWebService20061231">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
WewillnowrunthroughthemainsectionsofatypicalWSDL:
types:ThedatatypesexchangedareexpressedhereasanXMLschema.
message:Thissectiondetailsaboutthemessageformats(orthedocuments)exchanged.
portType:ThePortTypecanbelookedatastheabstractinterfacedefinitionfortheexposedservice.
binding:ThePortTypehastobemappedtospecificdataformatsandprotocols,whichwillbedetailedoutinthebindingsection.
port:TheportgivestheURLrepresentationoftheserviceendpoint.
service:Servicecancontainacollectionofportelements.
SinceJBIisbasedonWSDL,wewilldealwithmanyWSDLinstancesinthesubsequentchapters.
SOAPInwebservices,dataistransmittedoverthewireinSOAP.SOAPisanXML-basedmessagingprotocol.SOAPdefinesasetofrulesforstructuringmessagesthatcanbeusedforsimpleone-waymessagingandisusefulforperformingRPC-styleinteractions.EventhoughSOAPisnottiedtoanyparticulartransportprotocol,HTTPisthepopularone.
ASOAP-encodedRPCdialoguecontainsbotharequest
messageandaresponsemessage.LetusconsiderasimpleservicemethodthattakesaStringparameterandreturnsaStringtype:
publicStringhello(Stringparam);
TherespectiveSOAPrequestisshownasfollows:
<?xmlversion="1.0"encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance">
<soapenv:Body>
<ns1:hello
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/
encoding/"
xmlns:ns1="http://AxisEndToEnd.axis.apache.
binildas.com">
<in0xsi:type="soapenc:string"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
Binil
</in0>
</ns1:hello>
</soapenv:Body>
</soapenv:Envelope>
Similartotherequest,theSOAPresponseisshownbelow:
<?xmlversion="1.0"encoding="utf-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance">
<soapenv:Body>
<ns1:helloResponse
soapenv:encodingStyle="http://schemas.xmlsoap.
org/soap/encoding/"
xmlns:ns1="http://AxisEndToEnd.axis.apache.
binildas.com">
<helloReturnxsi:type="soapenc:string"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/
encoding/">
ReturnFromServer
</helloReturn>
</ns1:helloResponse>
</soapenv:Body>
</soapenv:Envelope>
AsisthecasewithWSDL,wewillbedealingwithmanyinstancesofSOAPrequestsandresponsesinourdiscussionsinthecomingchapters.Hence,letusnotdelveintotheintricaciesofWSDLandSOAP,astherearemanytextbooksdoingthesame.Letuscontinuewithourdiscussiononintegration.
ServiceOrientedIntegration(SOI)InChapter1,weidentifiedESBasanarchitecturalpatterndifferentfromtraditionalintegrationarchitectures,whichsupportstandards-basedservicesforintegration.GartneroriginallyidentifiedESBasthecorecomponentinanSOAlandscape.Gartnersays:
SOAwillbeusedinmorethan80%ofnewmission-criticalapplicationsandbusinessprocessesby2010
Anothermarketstrategystudy,conductedbyGartnerinSOArevealsthat:
TheESBcategorygrewby160%fromyear2004toyear2005
AsistruewithSOA,ESB-basedintegrationhasbeenincreasinglyusingwebservicesstandardsandtechnologiesforservicedescription,hosting,andaccessing.TheadvantageisthatwenotonlyreapallthebenefitsofESBarchitecture(explainedinChapter1),butalsomakesurethattheservicesexposedatthebusarecomplyingwithindustrystandards.ThismeansconsumersandprovidersmakesuseofexistingtoolsetsandframeworkstointeractwiththeESB.MostofthecurrentSOAtoolsetssupportwebservicesandrelatedtechnologies.Thisopensupawholelotofopportunitiesintheintegrationspacetoo,whichleadstoSOI.WhenwevirtualizeservicesintheESB,itisverycriticaltoprovideauniformecosystemforallkindofservices,whetheritiswritteninJava,or.NET,orC++.
Iftheservicesareasperthewebservicestandards,ESBcanprovidethemediationserviceswhichwillhelptointerconnecttheseservices.ExternalizingmediationlogicoutofservicestoanESBwillremovein-codecouplingbetweenservices.Tosumup,ourcurrentSOAinfrastructurestillexistswhichhostsservicesandtakescareofservicemanagementandgovernance.AlsoanESBprovidesSOIintheformofmediation,whichprovidescommunication(alongwithotherfeatures)betweenservices.
JBIinJ2EE—HowtheyRelateTheJava2EnterpriseEdition(J2EE)platformprovidescontainersforclientapplications,webcomponentsbasedonservletsandJavaServerPages(JSP),andEnterpriseJavaBeans(EJB)components.TheseJ2EEcontainersprovidedeploymentandruntimesupportforapplicationcomponents.Theyalsoprovideafederatedviewoftheplatform-levelservices,providedbytheunderlyingapplicationserverfortheapplicationcomponents.Inthissection,wewilllookatwhereJBIispositionedintheJ2EEstack.
Servlets,Portlets,EJB,JCA,andsoonTheworldofJavaisfabulous.Javaspeaksaboutportablecode(.classfiles),portabledata(JAXPandXML),portablecomponents(EJB),andnowportableservices(JAX-WS).However,untillnow,therewasnostandardwaybywhichwecoulddobusiness-levelintegrationacrossapplicationserversfrommultiplevendors.
Businessintegrationcanbedonewithbusinesscomponentsorwithbusinessservices.WeknowthatEJBcomponentscaninteroperateacrossmultiplevendor'sapplicationservers,andsimilaristhecasewithwebservices.WehavebeendoingintegrationwithinourtraditionalJ2EEprogrammingparadigminthepre-ESBera.Thechallengeofaccessing,integrating,andtransformingdatahaslargelybeendonebydevelopers
usingmanualcodingofJ2EEcomponentslikePOJO,EJB,JMS,andJCA.TheseJ2EEAPIsareoptimizedforbusinesspurposeprogramming,andnotforintegration.TheaftereffectisthattheJ2EEprogrammershavetouselow-levelAPIstoimplementintegrationconcerns.
Programmerscreateintegrationcodehavinghardcodeddependenciesbetweenspecificapplicationsanddatasources,whichareneitherefficientnorflexible.Hence,awaytodointegrationinalooselycoupledmannerandtoporttheintegrationsolutionasawholeismissing.Componentsandservicesareonlyapartoftheintegrationsolution.Italsoincludesthestrategytointegrate,thepatternsadaptedtorouteandtransformmessagesandsimilarartifacts.Allthesedifferfordifferentvendor'sproductsandJBIistryingtobringstandardizationacrossthisspace.
JBIandJCA—CompetingorComplementingTheJ2EEConnectorArchitecture(JCA)definesstandardsforconnectingtheJ2EEplatformtoheterogeneousEISsystems.ExamplesofEISsystemsincludeCICS,IMS,TPFsystems,ERP,databasesystems,andlegacyapplicationsnotwrittenintheJavaprogramminglanguage.TheJCAenablestheintegrationofEISswithapplicationserversandenterpriseapplicationsbydefiningadeveloper-levelAPIandavendor-levelSPI.TheSPIsenablesanEISvendortoprovideastandardresourceadapterforitsEIS.Theresourceadapterplugsintoanapplicationserver,thusprovidingconnectivity
betweentheEIS,theapplicationserver,andtheenterpriseapplication.
IfanapplicationservervendorhasextendeditssystemtosupporttheJCA,itisassuredofseamlessconnectivitytomultipleEISs.SofollowingJCA,anEISvendorneedstoprovidejustonestandardresourceadapter,whichhasthecapabilitytoplug-intoanyapplicationserverthatsupportstheJCA.HecannowbeassuredthathisEISwillplugintotheJ2EEcontinuum.
JCA-basedadaptersareusuallyusedtointegratecompliantESBswithEIS.Thismeans,byusingJCA,anEISvendorcanbeassuredthathisEIScanintegratewithcompliantESBs.JCAprovidesthemostefficientwayofresourcepooling,threadpooling,andtransactionhandlingonJMSandotherresourceadapters.Wehavealreadyseenthesimilaritiesbetweenamessagebusandaservicebus.Alongthoselines,wecanunderstandhowimportantistheMOMtechnologysuchasJMS.Hence,theimportanceJCAhasgotinintegration.
WealsoneedtounderstandonesubtledifferencebetweenJBIandJCAhere.JCAisdesignedtosupportthetraditionalrequest-responsemodel,butfailstosupportcomplexlongrunningtransactionsandintegrationscenarios.Muchback-endintegrationdoesnotalwaysfitwellwiththesynchronousrequest-responsemodelandJBIhasgotsomethingelsetoofferhere.JBIisbasedonamediatedmessageexchangepattern.Thatis,whenacomponentsendsamessagetoanothercomponent,themessageexchangeismediatedbytheJBI
infrastructure.Aswewillseeshortly,JBIsupportsmultiplemessageexchangepatterns.Moreover,JBI-basedESBswillgivemorefunctionalitiessuchasservicecomposition,BPM,etc.,whichmakessenseinhandlingback-endintegrationandlongrunningtransactions.
JBI—aNewStandardEveryorganizationwouldliketoleverageexistingITstafftoruntheirintegrationeffortsimilartotheirdailyITdevelopmentandoperations.However,integrationisadifferentartthannormalsoftwaredevelopmentandthatiswhywehaveintegrationarchitects.Thatdoesn'tmeanintegrationexpertshavetobeexpertsinvendorX'sproduct,andarebacktonovice-levelinvendorY'sproduct.Ifthishastohappen,weneedtodosimilaractivitiesacrossmultiplevendor'sproducts.
Aswealreadydiscussed,integrationisnotthatsimpleasitinvolvesintegrationarchitectures,integrationpatterns,andMOMexpertise.Weneedtobuildtheextraintelligentadaptersaroundservicesandendpoints.Theseadaptersaretoworkintandemwiththeplatformprovidertogivelow-levelfeatureslikecommunication,session,state,transport,androuting.Thus,businessintegrationisnotlimitedbyjustapplicationprogramming,butinvolvescomponentsandengineeringprocessesattheapplicationandplatforminterface-level.Hence,tomakeintegrationartifactsportable,eventheintegrationvendors(whodealwithplatformservices)haveabigparttoplay.Thisiswhereweneedstandardizationascomponentsandadaptersshouldbeportableacrossseveral
vendorproducts.
Letmetrytoexplainthispointabitfurther,asthisistheprimeconcernintoday'sintegrationinitiatives.SincetheinceptionofJ2EE,wehavebeenusingmultipleJ2EEcontainersfromdifferentvendors.MostoftheseJ2EEcontainersalsohaveanintegrationstack,whichcanbeeitherpluggedintotheirexistingJ2EEcontainersorcanberunasstandalone.WebsphereBusinessIntegration(WBI)messagebrokerandBEAAqualogicServiceBus(ALSB)arejustafewoftheminthelist.Itistrue,thatmostoftheseintegrationstackstoosupportstandard-basedintegration,followingSOAprinciplesandpatterns.Whatabouttheintegrationartifactsassuch?
WhenIsayintegrationartifacts,Irefertoanyintegrationlibrariesavailable,oranycustomconfigurationthedevelopersdototheabovelibraries,thepackaginganddeploymentartifactstheygenerate.Inotherwords,ifwecreatea.jaror.earfilecontainingsomeintegrationsolutioninALSB;canweportittoWBIlater?Ileavethisquestionopenfortheusercommunityoftheseframeworkstoanswer.So,whathashappenedhere?Asalways,theevolutionofstandardslagsbehindtheevolutionoftechnology.Hence,evenbeforeJBI,wehadmultipleprogrammingparadigmstosolveintegrationissues,butthentheyweretiedtothevendor'senvironment.ThepromiseofJBIistobringportabilityacrossdifferentJBIcontainersfortheintegrationartifacts.
JBIinDetailInChapter1,wediscussedESBarchitecturewhichcanfacilitatethecollaborationbetweenservices.JBIprovidesacollaborationframeworkwhichprovidesstandardinterfacesforintegrationcomponentsandprotocolstopluginto,thusallowingtheassemblyofSOIframeworks.
JSR208JSR208isanextensionofJ2EE,butitisspecificforJBIServiceProviderInterfaces(SPI).SOAandSOIarethetargetsofJBIandhenceitisbuiltaroundWSDL.IntegrationcomponentscanbepluggedintotheJBIenvironmentusingaservicemodelbasedonWSDL.ServicecompositionisamajortargetinESBarchitectureandtheJBIenvironmentaggregatesmultipleservicedefinitionsintheWSDLformintothemessageinfrastructure.
Inthecontextofalargerservicecomposition,wehavemultiplepartners(serviceprovidersorserviceconsumers)andthemetadataforinteractionoftheseindividualpartnersaretermedasthebusinessprotocol.Themetadataofchoreographyplayedbyabusinessprocessinabusinessprotocolistermedastheabstractbusinessprocess.Partnerprocessesinteractwitheachotherbylookingatabstractbusinessprocess;itistheESB'sjobtorealizethisabstractbusinessprocess.JSRaimstomakethisabstractbusinessprocessdefinitionportable.Thismeansthewiringdetailsbetweencomponentsinaservicecompositionscenariocanbe
extractedintoaseparatelayeranditisthislayerwhichwearespeakingaboutJSR208.Thus,JSR208orJBIisafoundationforrealizingSOI.
JSR208mandatesthefollowingforJBIcomponents:
Portable:ComponentsareportableacrossJBIimplementations.
Manageable:Componentscanbemanagedinacentralizedmanner.
Interoperable:Componentsshouldbeabletoprovideservicetoandconsumeservicesfromothercomponents,despitethefactthattheycomefromdifferentsourcesandtransportprotocols.
JBINomenclatureThissectionhelpsustounderstandthemajorcomponentsinJBIarchitectureandtheirroleswithreferencetothefollowingfigure:
Themajorcomponentsareexplainedhere:
JBIenvironment:AJBIenvironmentisasingleJavaVirtualMachine(JVM)wherewecandeployintegrationartifacts.ThisJBIcanbeastandaloneESBoranESBembeddedintheJVMofanapplicationserver.Inthelattercase,evenanEJBcomponentdeployedinanapplicationservercanfunctionasaproviderorconsumertotheESB,thusfurthernarrowingdownthebridgebetweentraditionalJ2EEapplicationserversandtherelativelynewESB.
ServiceEngine(SE):SEsareserviceprovidersorserviceconsumersdeployedlocallywithinaJBIenvironment.Theyprovidetheactualbusinesslogicliketransformation.TransformationservicecanbedonewiththehelpofanXSLTenginebyusingastylesheet.AnotherenginemayuseJCAtogiveadataaccessservice,orBusinessProcessExecutionLanguage(BPEL),orevencustomlogictointegratelegacycodelikethatinCICSormainframe.
BindingComponents(BC):BCprovidecommunicationsprotocolsupportandtheyarenormallyboundtocomponentsdeployedremotelyfromtheJBI
runtime.Infact,nothingpreventsauserfromdefiningabindingforalocalserviceinthecasewhereitcloselyresemblesSE.ThusBCprovidesremoteaccesstoservicesforremoteserviceprovidersandconsumers.
NOTENOTE
ThedistinctionbetweenSEandBCisimportantforvariouspragmaticreasons.Mainly,itseparatesservicelogicfrombindingprotocol.Thisfacilitatesreusability.
JBIContainer:Similartothecontainerinanapplicationserver,aJBIenvironmentbyitselfisaJBIcontainer.ThiscontainerhostsSEandBC.TheinterestingpartisaSEisagainacontainerforenginespecificentitieslikeXSLTengine,stylesheets,rulesengines,andscripts.Thus,aJBIenvironmentisacontainerofcontainerswhereasaserviceengineisacontainerforhostingWSDLdefinedprovidersandconsumerslocaltotheJBI.
Normalizedmessage:Anormalizedmessageconsistsoftwoparts—theactualmessageinXMLformat,andmessagemetadatawhichisalsoreferredtoasthemessagecontextdata.Themessagecontextdatahelpstoassociateextrainformationwithaparticularmessage,asitisprocessedbybothplug-incomponentsandsystemcomponentsinthebus.
Normalizedmessagerouter(NMR):ThenerveoftheJBIarchitectureistheNMR.Thisisabusthroughwhichmessagesflowineitherdirectionfromasourcetoadestination.Thespecialtyofthisrouteristhatmessagesarealwaysinanormalizedformat,irrespectiveofthesourceordestination.NMRthusactsasalightweightmessaginginfrastructurewhichfacilitatesactualmessageexchangeinalooselycoupledfashion.NMRprovidesvaryingQOSfunctionalitiesandthethreelevelsofmessagedeliveryguaranteeprovidedbyNMRarelistedasfollows:
Besteffort:Messagemaybedeliveredonlyonceormorethanonce,oreventhemessagecanbedropped.
AtLeastOnce:Messagehastobedeliveredonceormore,butcannotbedropped.Hence,duplicatescanexist.
Onceandonlyonce:Itisguaranteedthatmessageswillbedeliveredonceandonlyonce.
Pluggablecomponents:ThelooselycoupledfeatureofESBisduetothepluggablearchitectureforservicecomponents.TherearetwobroadcategoriesofpluggablecomponentscalledSEandBC.Pluggablecomponentscanplaytheroleofserviceprovider,serviceconsumer,orboth.PluggablecomponentsareconnectedtotheNMRthroughaDeliveryChannel.
Serviceprovidersandserviceconsumers:TherearemainlytworolesplayedbypluggablecomponentswithinanESB,theserviceproviderandserviceconsumer.Componentscanactasbothaproviderandaconsumeratthesametime.ServicedefinitionisavailableintheformofWSDLandthisistheonlysharedartifactbetweenprovidersandconsumers.SinceendpointinformationisnotsharedbetweenprovidersandconsumersintheESB,looselycoupledintegrationisfacilitated.
Itistobenotedthatasingleservicedefinitionmaybeimplementedbymultipleproviders.Similarly,aconsumer'sservicedefinitionofinterestmightbeprovidedbymultipleproviderstoo,inESBarchitecture.Moreover,theroleofbothproviderandconsumercanbeplayedbythecomponenteitherdirectlyorthroughaproxyforaremoteservice.
DeliveryChannel(DC):DCconnectsamessagesourceandadestination.ThemessaginginfrastructureortheNMRisthebusformessageexchangeformultipleserviceprovidersandconsumers.Hencewhenaserviceproviderhasgotinformationtocommunicate,itdoesn'tjustflingthemessageintotheNMR,butaddsthemessagetoaparticularDC.Similarly,amessageconsumerdoesn'tjustpickitupatrandomfromthemessagingsystem.Instead,theconsumerreceivesthemessagefromaparticularDC.ThusDCsarelogicaladdressesintheESB.
Provider—ConsumerContractIntheJBIenvironment,theproviderandconsumeralwaysinteractbasedonaservicesmodel.Aserviceinterfaceisthecommonaspectbetweenthem.WSDL1.1and2.0areusedtodefinethecontractthroughtheservicesinterface.
ThefollowingfigurerepresentsthetwopartsoftheWSDL
representationofaservice:
IntheAbstractModel,WSDLdescribesthepropagationofamessagethroughatypesystem.AmessagehassequenceandcardinalityspecifiedbyitsMessageExchangePattern(MEP).AMessagecanbeaFaultMessagealso.AnMEPisassociatedwithoneormoremessagesusinganOperation.AnInterfacecancontainasingleOperationoragroupofOperationsrepresentedinanabstractfashion—independentofwireformatsandtransportprotocols.
AnInterfaceintheAbstractModelisboundtoaspecificwireformatandtransportprotocolviaBinding.ABindingisassociatedwithanetworkaddressinanEndpointandasingleServiceintheconcretemodelaggregatesmultipleEndpointsimplementingcommoninterfaces.
DetachedMessageExchange
JBI-basedmessageexchangeoccursbetweenaProviderandConsumerinadetachedfashion.Thismeans,theProviderandConsumerneverinteractdirectly.Intechnicalterms,theyneversharethesamethreadcontextofexecution.Instead,theProviderandConsumeruseJBINMRasanintermediary.Thus,theConsumersendsarequestmessagetotheNMR.TheNMR,usingintelligentroutersdecidesthebestmatchedserviceprovideranddispatchesthemessageonbehalfoftheConsumer.TheProvidercomponentcanbeadifferentcomponentorthesamecomponentastheConsumeritself.TheProvidercanbeanSEoraBCandbasedonthetypeitwillexecutethebusinessprocessbyitselfordelegatetheactualprocessingtotheremotelyboundcomponent.TheresponsemessageissentbacktotheNMRbytheProvider,andtheNMRinturnpassesitbacktotheConsumer.Thiscompletesthemessageexchange.
ThefollowingfigurerepresentstheJBI-basedmessageexchange:
Therearemultiplepatternsbywhichmessagesareexchanged,whichwewillreviewshortly.
Provider—ConsumerRoleThoughaJBIcomponentcanfunctionasaConsumer,aProvider,orasbothaConsumerandProvider,thereisclearcutdistinctionbetweentheProviderandConsumerroles.Theserolesmaybeperformedbybindingsorengines,inanycombinationofthetwo.WhenabindingactsasaserviceProvider,anexternalserviceisimplied.Similarly,whenthebindingactsasaserviceConsumer,anexternalConsumerisimplied.Inthesameway,theuseofaServiceEnginesineitherroleimpliesalocalactorforthatrole.
Thisisshowninthefollowingfigure:
TheProviderandConsumerinteractwitheachotherthroughtheNMR.Whentheyinteract,theyperformthedistinctresponsibilities(notnecessarilyinthesameorder).
Thefollowingisthelistofresponsibilities,performedbytheProviderandConsumerwhileinteractingwithNMR:
1. Provider:Oncedeployed,theJBIactivatestheserviceproviderendpoint.
2. Provider:ProviderthenpublishestheservicedescriptioninWSDLformat.
3. Consumer:Consumerthendiscoverstherequiredservice.Thiscanhappenatdesigntime(staticbinding)orruntime(dynamicbinding).
4. Consumer:Invokesthequeriedservice.
5. ProviderandConsumer:SendandrespondtomessageexchangesaccordingtotheMEP,andstateofthemessageexchangeinstance.
6. Provider:Providestheservicebyrespondingtothefunctioninvocations.
7. ProviderandConsumer:Respondswithstatus(faultordone)tocompletethemessageexchange.
Duringruntimeactivation,aserviceprovideractivatestheactualservicesitprovides,makingthemknowntotheNMR.Itcannowrouteserviceinvocationstothatservice.
javax.jbi.component.ComponentContextcontext;
//Initializedvia.AOP
javax.jbi.messaging.DeliveryChannelchannel=
context.getDeliveryChannel();
javax.jbi.servicedesc.ServiceEndpoint
serviceEndpoint=null;
if(service!=null&&endpoint!=null)
{
serviceEndpoint=context.activateEndpoint
(service,endpoint);
}
TheProvidercreatesaWSDLdescribedserviceavailablethroughanendpoint.AsdescribedintheProvider-Consumercontract,theserviceimplementsaWSDL-basedinterface,whichisacollectionofoperations.Theconsumercreatesamessageexchangetosendamessagetoinvokeaparticularservice.Sinceconsumersandprovidersonlysharetheabstractservicedefinition,theyaredecoupledfromeachother.Moreover,severalservicescanimplementthesameWSDLinterface.Hence,ifaconsumersendsamessageforaparticularinterface,theJBImightfindmorethanoneendpointconformingtotheinterfaceandcanthusroutetothebest-fitendpoint.
MessageExchangeAmessageexchangeisthe"MessagePacket"transferred
betweenaconsumerandaproviderinaserviceinvocation.Itrepresentsacontainerfornormalizedmessageswhicharedescribedbyanexchangepattern.Thusmessageexchangeencapsulatesthefollowing:
Normalizedmessage
Messageexchangemetadata
Messageexchangestate
Thus,messageexchangeistheJBIlocalportionofaserviceinvocation.
ServiceInvocationAnend-to-endinteractionbetweenaserviceconsumerandaserviceproviderisaserviceinvocation.Serviceconsumersemployoneormoreserviceinvocationpatterns.ServiceinvocationthroughaJBIinfrastructureisbasedona'pull'model,whereacomponentacceptsmessageexchangeinstanceswhenitisready.Thus,onceamessageexchangeinstanceiscreated,itissentbackandforthbetweenthetwoparticipatingcomponents,andthiscontinuestillthestatusofthemessageexchangeinstanceiseithersetto'done'or'error',andsentonelasttimebetweenthetwocomponents.
MessageExchangePatterns(MEP)
Serviceconsumersinteractwithserviceprovidersformessageexchangeemployingoneormoreserviceinvocationpatterns.TheMEPdefinesthenames,sequence,andcardinalityofmessagesinanexchange.Therearemanyserviceinvocationpatterns,and,fromaJBIperspective,anyJBI-compliantESBimplementationmustsupportthefollowingfourserviceinvocations:
One-Way:Serviceconsumerissuesarequesttotheserviceprovider.Noerror(fault)pathisprovided.
ReliableOne-Way:Serviceconsumerissuesarequesttotheserviceprovider.Providermayrespondwithafaultifitfailstoprocesstherequest.
Request-Response:ServiceConsumerissuesarequesttotheserviceprovider,withexpectationofresponse.Providermayrespondwithafaultifitfailstoprocessrequest.
RequestOptional-Response:Serviceconsumerissuesarequesttotheserviceprovider,whichmayresultinaresponse.Bothconsumerandproviderhavetheoptionofgeneratingafaultinresponsetoamessagereceivedduringtheinteraction.
TheaboveserviceinvocationscanbemappedtofourdifferentMEPsthatarelistedasfollows.
In-OnlyMEPIn-OnlyMEPisusedforone-wayexchanges.ThefollowingfigurediagrammaticallyexplainstheIn-OnlyMEP:
IntheIn-OnlyMEPnormalscenario,thesequenceofoperationsisasfollows:
ServiceConsumerinitiateswithamessage.
ServiceProviderrespondswiththestatustocompletethemessageexchange.
IntheIn-OnlyMEPnormalscenario,sincetheConsumerissuesarequesttotheProviderwithnoerror(fault)path,anyerrorsattheProvider-levelwillnotbepropagatedtotheConsumer.
RobustIn-OnlyMEPRobustIn-OnlyMEPisusedforreliable,one-waymessageexchanges.Ithasgottwousagescenarios—thenormalscenarioandthefaultscenario.
Normalscenario:IntheRobustIn-OnlyMEPinthenormal(withoutanyfault)scenario,thesequenceofmessageexchangesissimilartothatofIn-OnlyMEP.Thedifferencecomestoplayonlyinthecasewherethereisan
errorattheProvider-level,whichwillbedescribedasthenextitem.
ThefollowingfigureexplainstheRobustIn-OnlyMEP—Normalscenario:
IntheRobustIn-OnlyMEP—Normalscenario,thesequenceofoperationsisasfollows:
ServiceConsumerinitiateswithamessage.
ServiceProviderrespondswiththestatustocompletethemessageexchange.
Faultscenario:IntheRobustIn-OnlyMEPinthefaultscenario,theConsumerissuesarequesttotheProviderandtheProviderwillrespondwithafaultinsteadofthenormalresponse.
ThefollowingfigureexplainstheRobustIn-OnlyMEP—Faultscenario:
IntheRobustIn-OnlyMEP—Faultscenario,thesequenceofoperationsisasfollows:
ServiceConsumerinitiateswithamessage.
ServiceProviderrespondswithafault.
ServiceConsumerrespondswiththestatustocompletethemessageexchange.
So,whatyouneedtonoteisthat,intheRobustIn-OnlyMEP—Normalscenario,theexchangeisterminatedwhentheProviderrespondswithstatustocompletethemessageexchange,whereasintheRobustIn-OnlyMEP—Faultscenario,theexchangeisterminatedwhentheConsumerrespondswiththestatustocompletethemessageexchange.Thestatustocompletethemessageexchangeeveninthecaseoffaultscenario,bringsrobustnesstoit.
In-OutMEPIn-OutMEPisusedforarequest-responsepairofservice
invocations.HeretheConsumerissuesarequesttotheProvider,withexpectationofaresponse.Ithasgottwousagescenarios—thenormalscenarioandthefaultscenario.
Normalscenario:IntheIn-OutMEPinthenormal(withoutanyfault)scenario,theConsumerissuesarequesttotheProvider,withexpectationofaresponse.TheProviderrespondswiththenormalresponse.
ThefollowingfigureexplainstheIn-OutMEP—Normalscenario:
IntheIn-OutMEP—Normalscenario,thesequenceofoperationsisasfollows:
ServiceConsumerinitiateswithamessage.
ServiceProviderrespondswithamessage.
ServiceConsumerrespondswiththestatustocompletethemessageexchange.
Faultscenario:IntheIn-OutMEPinthefaultscenario,theConsumerissuesarequesttotheProviderwithexpectationofaresponseandtheProviderwillrespondwithafaultinsteadofthenormalresponse.
ThefollowingfigureexplainstheIn-OutMEP—Faultscenario:
IntheIn-OutMEP—Faultscenario,thesequenceofoperationsisasfollows:
ServiceConsumerinitiateswithamessage.
ServiceProviderrespondswithafault.
ServiceConsumerrespondswiththestatustocompletethemessageexchange.
In-Optional-OutMEPIntheIn-Optional-OutMEP,theserviceConsumerissuesarequesttotheserviceProvider,whichmayormaynotresultinaresponse.BoththeConsumerandtheProviderhavetheoptionofgeneratingafaultinresponsetoamessagereceivedduringtheinteraction.
One-Way:IntheIn-Optional-OutMEP—One-Wayscenario,theserviceConsumerissuesarequesttotheserviceProvider.TheProviderneitherreturnsanyresponse,norgeneratesanyfault.
ThefollowingfigureexplainstheIn-Optional-OutMEP—One-Wayscenario:
IntheIn-Optional-OutMEP—One-Wayscenario,thesequenceofoperationsisasfollows:
ServiceConsumerinitiateswithamessage.
ServiceProviderrespondswiththestatustocompletethemessageexchange.
Two-Way:IntheIn-Optional-OutMEP—Two-Wayscenario,theserviceConsumerissuesarequesttotheserviceProvider.TheProviderthenreturnsaresponse.
ThefollowingfigureexplainstheIn-Optional-OutMEP—Two-Wayscenario:
IntheIn-Optional-OutMEP—Two-Wayscenario,thesequenceofoperationsisasfollows:
ServiceConsumerinitiateswithamessage.
ServiceProviderrespondswithamessage.
ServiceConsumerrespondswiththestatustocompletethemessageexchange.
Provider-Fault:IntheIn-Optional-OutMEP—Provider-Faultscenario,theserviceConsumerissuesarequesttotheserviceProvider.TheProvidergeneratesafaultinsteadofthenormalresponse.
ThefollowingfigureexplainstheIn-Optional-OutMEP—Provider-Faultscenario:
IntheIn-Optional-OutMEP—Provider-Faultscenario,thesequenceofoperationsisasfollows:
ServiceConsumerinitiateswithamessage.
ServiceProviderrespondswithafault.
ServiceConsumerrespondswiththestatustocompletethemessageexchange.
Consumer-Fault:IntheIn-Optional-OutMEP—Consumer-Faultscenario,theserviceConsumerissuesarequesttotheserviceProvider.TheProviderthenreturnsaresponse.TheConsumergeneratesafaultwhileacceptingtheresponse.
ThefollowingfigureexplainstheIn-Optional-OutMEP—Consumer-Faultscenario:
IntheIn-Optional-OutMEP—Consumer-Faultscenario,thesequenceofoperationsisasfollows:
ServiceConsumerinitiateswithamessage.
ServiceProviderrespondswithamessage.
ServiceConsumerrespondswithafault.
ServiceProviderrespondswiththestatustocompletethemessageexchange.
WhereconsideringaMEP,wealwaysconsidertheserviceprovider'spointofview.Thus,amessagetargetedtowardstheproviderinanIn-OnlyMEPisthe'In'partoftheMEP.Onthecontrary,ifamessageistargetedtowardstheconsumer,itisinfacttargetedoutfromtheprovider,andhenceisthe'Out'partoftheMEP.
Thus,dependingupontheroleofthecomponentinthemessageexchange,theappropriatepartormessageiscreated,initialized,andsenttothedeliverychannel.ForanIn-Outscenario,thetypicalstepsareasfollows:
javax.jbi.messaging.InOutinout=
createInOutExchange(new
QName(addressNamespaceURI,addressLocalPart),
null,null);
inout.setProperty("correlationId",id);
//setotherproperties
javax.jbi.messaging.NormalizedMessagenMsg=
inout.createMessage();
//
nMsg.setProperty(Constants.PROPERTY_SSN_NUMBER,
ssnNumber);
//setotherproperties
inout.setInMessage(nMsg);
send(inout);
ESB—WillitSolveallOurPainPointsInChapter1,weintroducedESBandalsolookedintowhatJBIhasgottoofferhere.IfyouarefamiliarwithSOAprinciples,onesubtlefact,whichisevidentnowisthatESBorJBIarenotanendbythemselves,butameanstowardsanend(whichisSOA).AnESBisnotrequiredtobuildanSOA,norisJBIrequiredforESBorSOA.However,allofthemhavesomethingincommonusingJBI—wecanbuildstandardcomponentstobedeployedintoESBarchitectures.Thus,JBIbyitselfisoneofthewaysbywhichwecanattainSOA.Thereisalsoacaveattothis—justfollowingJBIorESBwillnotguaranteethatyouattainSOA.Increasingly,youwillhearrequestsfromyourprojectstakeholderstoimplementanESBwithoutconsideringSOAasawhole,suchthattheywant
immediatesolutions.ItistechnicallyfeasibletobuildESB,whichactaspipesinterconnectingsystems,butthesuccessofsuchESBarchitectureswithoutconsideringtheSOAlandscape,whichitissupposedtobeapartof,willbedifficulttomeasure.
SummaryJBIisthenewintegrationAPIintroducedintheJ2EEworld.ItisagreatenablerforSOAbecauseitdefinesESBarchitecture,whichcanfacilitatethecollaborationbetweenservices.Itprovidesforlooselycoupledintegrationbyseparatingouttheprovidersandconsumerstomediatethroughthebus.
TheNMRprovidesacommonintegrationchannelthroughwhichthemessagesflow.ServicesarepublishedinthebususingtheWSDLstandard.Providersandconsumersarethedifferentrolestakenbytheintegrationcomponentswithrespecttothebus,whenpluggedintotheJBIbus.MessageexchangetakesplacethroughdifferentMEPs,eachprovidingdifferentlevelsofreliability.
ThenextchapterwillintroduceaJBIcontainer.Bereadytowetyourhandswithsomecodetoo—tobuildanddeployyourfirstJBIsample.
Chapter3.JBIContainer—ServiceMixThefirsttwochaptersintroducedESBandJBIrespectively,withmuchtheoryandlessofcode.Justlikeme,youtoomighthavecomeacrossalotofwhitepapersandpointofviewsontheabovetwotechnologies.However,whenwewanttoactuallyimplementthemintoourtechnicalarchitectures,weneedworkingcodedemonstratingboth.
JustlikeanyotherJavaAPIs,servletorEJB,foraJBIAPItoo,weneedconcreteimplementation.TherearemanyimplementationssupportingESBarchitecturesavailableinthemarkettoday.AcoupleofthemcaninteroperatewiththeJBIAPIwhereasafewotherstackleJBIonthesideofquiteadifferentprogrammingmodel.ServiceMixisanopen-sourceESBplatforminJavaprogramminglanguage,builtfromthegroundupwithJBIAPIsandprinciples.
Duetothereasonquotedinthefirstparagraph,wewilluseServiceMixtobetterunderstandJBIandESB.Hence,mostofthesubsequentchaptersinthisbookwillintroducenewscenariosorpatternsinbusinessintegrationandthentrytosolvethemintheJBIwaywithcodesamplesinServiceMix.Whatyouneedtokeepinmindisthateachoftheseintegrationtechniquescanbeusedasstandalone,orinintegrationwithotherscenariosandpatternstobringoutan
integrationsolutionusingESBarchitecturalblueprints.
Wewillcoverthefollowinginthischapter:
IntroductiontoServiceMix—theJBIcontainer
FewotherESBproductsavailableinthemarket
WheretodownloadandhowtoinstallServiceMix
FirstJBIsample
ServiceMix—UndertheHoodServiceMixisbasedonSOAandEventDrivenArchitecture(EDA),andhenceprovidesaplatformforSOI.LetuslookmoreintothisJBIcontainer.
SalientFeaturesServiceMixisbuiltbasedontheJBI(JSR208)specificationandhencecomponentsareportableacrossESBcontainers.ServiceMixislightweightandcanberunstandaloneorembeddedinothercontainers.SinceitisJBI-compliant,ServiceMixcanitselfbepluggedintoanotherJBI-compliantESB.ServiceMixhasintegratedSpringsupport,andhencewecanintegrateandwireservicesandcomponentsinSpring-likeconfigurationfiles.TheJBIstandardspeaksaboutstandarddeploymentunitformatsintheformofserviceunitandserviceassembly.ThismeanswecanhotdeployanyJBI-compliantBPELengine(orsetofBPELfilesintoaBPELengine),ruleengine,transformationengine,routingengine
(eventhoughServiceMixdoesitsownrouting),scriptingengine,orotherintegrationcomponent(suchasspecificJBIbindingcomponents)directlyintoServiceMix.
ServiceMixArchitectureJBIisaspecificationandvendorsarefreetoimplementtheJBIcontainerintheirownways,justliketherearemultipleEJBcontainersbroughtoutbymultiplevendors.Eachvendor'scontainerhastorespecttheJBIAPIsifitistobeJ2EE-compliant.ServiceMixisaJBIcontainerandhenceiscompliantwiththeJBIAPIs,buthasgotitsownfeaturesandwayofroutingmessages.LetuslookmoreintotheinternalarchitectureofServiceMix.
ArchitectureDiagramJBIcompliancyisthemainfeatureoftheServiceMixarchitecture.Thismeans,asshowninthefollowingarchitecturediagram,ServiceMixisanopenarchitecture.So,anyJBI-compliantcomponentcanfitintothearchitecture.Moreover,thearchitectureisalsoscalablefromadeploymentperspective.Mosthub-and-spokearchitecturesuffersfromthesinglepointoffailure.However,ServiceMix,duetotheopennature,canalsocollaboratewithanyotherESB,effectivelypluggingitsroutingcapabilitiesintootherESBcores,thusgeneratingafederationofservicecontainers.
NormalizedMessageRouterFlowsComponentspluggedintoServiceMix,whethertheyarelocalorremotetoit,interactwitheachotherthroughtheNMR.Moreover,ServiceMixisbasedonMOMprinciples.Hence,messagesareexchangedbetweencomponentsthroughtheNMRusingasuitableMEP.Toexchangemessages,differentmessagedispatchpoliciescanbeadoptedwhichwilldecidetheQOSofthemessageexchanges.EachofthesepoliciesisabstractedoutasdifferentNMRflowsinServiceMix.DependinguponthespecificusecaseyouwanttoimplementusingServiceMix,theactualNMRflowcanbespecified.ItisalsotobenotedthatdifferentNMRflowswillexhibitdifferentcapabilitiesintermsofcrosscuttingconcernssuchasmessagebrokeringandmessagebuffering.
ServiceMix,atpresent,providesfourNMRflowtypes:
Straightthrough(ST)flow:STPisanalogoustotheB2Btradingprocess
forcapitalmarketsandpaymenttransactionsdoneelectronically.thisisdonewithoutneedingtorekeyormanuallyintervenetheSTPflow.AmessageexchangeisroutedSTfromthesourcetothedestination.Thereisnostagingorbufferingofmessagesenroute.ThiskindofflowispreferredforcaseswheretheServiceMixcontainerisdeployedwithsimpleflows(nostate)orisembedded.Sincethereisnostagingorbuffering,latencywillbeaslowaspossible.
ThefollowingfigurerepresentsaSTflow:
StagedEventDrivenArchitecture(SEDA)flow:SEDAdecomposesaserviceintomultiplestages,whereeachstageisanevent-drivenservicecomponentthatperformssomeaspectofprocessingtherequest.Eachstagecontainsasmall,dynamicallysizedthreadpooltodriveitsexecution.SEDAprovidesnonblockingI/Oprimitivestoeliminatethemostcommonsourcesoflongblockingoperations.
IntheServiceMixSEDAflow,wehaveasimpleeventstagingbetweentheinternalprocessesintheNMRbroker.SEDAisthedefaultflowinServiceMixandissuitedforgeneraldeployment,astheadditionalstagingcanbufferexchangesbetweenheavilyroutedtocomponents(wherestatemaybeused),forexample.
ThefollowingfigurerepresentsaSEDAflow:
JavaMessageService(JMS)flow:IntheServiceMixJMSflow,wecanleveragethetestedandprovenmethodologyofMOMtoaddressscalabilityorfailover.UsingJMSflow,multipleServiceMixcontainerscancollaborateinaclusterorotherwise,toprovidecomponentandservicereplication.WhenwedeployacomponenteitherasaPOJOorasanarchivecomponentintoaJMSflowconfiguredServiceMixcontainer,allthecontainersintheclusterarenotifiedofthedeployment.TheJMSNMRflowcanhandleautomaticrouting(andfailover)ofmessageexchange(s)betweenmultiplecontainerinstances.
ThefollowingfigurerepresentsaJMSflow:
JCAFlow:TheServiceMixJCANMRflowisverymuchsimilartotheJMSflow.Infact,ServiceMixusesJMSsessionsastheunderlyingmechanismsothatmultipleServiceMixcontainerscancollaborateinacluster.Inaddition,JCAprovidessupportforXAtransactionswhensendingandreceivingJBIexchanges.
ThefollowingfigurerepresentsaJCAflow:
OtherESBsTherearequiteafewESBframeworksavailableintheindustrytodayandwewilllistafewofthemhereforcompletenessofourdiscussion.
MuleMuleisdefinedasalightweightmessagingframeworkfunctioningasanESB.ThisESBfeaturesadistributedobjectbroker,whichcanhandleinteractionsbetweendifferentsystems,applications,components,andservices,irrespectiveofthetransportprotocolsandbindingtechnologies.MuleprovidesaUniversalMessageObject(UMO)API(insideorg.mule.umopackage),awayforcomponentstointeractwithoutneedingtoknowabouttheprotocolordeliverymechanismsofinformationpassedbetweenthem.
MulecanhoststandardPOJOs,whichcanbemanagedfromcontainerssuchasSpring,Pico,andPlexusorfromtheclasspath,oranyothersource.MulehasaJBIinterfacewhichwillcomplimentandnotcompetewithServiceMix.MuleandJBIfunctionsdifferentlyinthewaytheyexchangemessageformats.
JBIisXMLandWSDLcentricwhereasMulemakesnoassumptionsaboutthemessagetype,sothatyoucaneasilyuseStrings,binaries,MIME,XML,objects,streams,oramixturewithoutanyextradevelopment.TostreamallMulesupportedformatsthroughaJBI-compliantcontainer,suitabletunnelingmayneedtobedoneorbinarylikemessagesneedtobetransformedintoXMLformat.Thus,JBIbringsWSDLcentricstandardization,whereasMuleprovidesmoreoptionsintermsofflexibility.
Celtix
CeltixisanESBwhichisJBI-compliant.LeveragingCeltix,developerscanbuildserviceenginesandbindingcomponents.SinceCeltixisJBI-compliant,theserviceenginesandbindingcomponentstooareJBI-compliant,hencecanbedeployedintoanotherthird-partyJBIcontainer.Similarly,CeltixisalsoafullfledgedJBI-compliantcontainer.Thismeansanythird-partyJBI-compliantserviceenginesandbindingcomponentscanbedeployedintoaCeltixESBcontainer.
EventhoughCeltixisJBI-compliant,JBIobjectivesareslightlydifferentfromthatofCeltix.Themaindifferencesarelistedasfollows:
AJBI-compliantserviceengineorbindingcomponentisessentiallyablackboxandthereislittleornocontroloverthemessageflowwithinthem.
ThenormalizedmessageformatspecifiedbyJBIisXMLandhenceexchangeofnonXML-basedmessageformats,likethatofCORBA,willbedifficultandattheveryleastwillrequirethebinaryformattedmessagestobetransformedintoanXMLformat.
Forbindingcomponentsandserviceenginesintheroleofprovider,WSDListhecontractinJBI.WSDLmaynotbeappropriateinallscenarios.Forexample,inthecaseoflegacyintegrationinvolvingproprietaryAPIcalls.
ObjectreferencesandcallbacksarenotspecifiedinJBI.
Celtix,beingJBI-compliant,isalsotryingtobridgetheabovementionedgaps,whichareyettobeprovenasgapsbyindustrybasedonrealintegrationscenarios.
IonaArtixArtixESBserviceenablesintegrationexistingserversdirectly
attheendpointswithouttheneedforaseparateintegrationserver,thusfacilitatingmacro-levelintegration.ArtixisaplatformindependentinfrastructureproductforbuildingJava,C/C++,andmainframewebservices.Allfeaturescanbeconfigureddynamicallyprovidingmaximumflexibilityforimplementingascalable,fullydistributedSOA.ArtixESBprovidedtoolsincludeArtixDesigner,Codegenerators,andManagementConsoletomakecreating,testing,anddeployingserviceseasy.TheArtixESBcontainerisaserverthatallowsyoutorunserviceplug-ins,eitherthosethatcomewithArtixESBorcustomcomponents,andprovidesthreading,resourcemanagement,andnetworkmanagementservices.However,Artixtechnicalspecificationdoesn'tspeakaboutJBI,nordotheyclaimthatArtixcomponentsinteroperatewithotherJBIcontainers.
PEtALSPEtALSisanopen-sourceJBIplatform.PEtALSisbasedonJSR-208andprovideslightweightandpackagedintegrationsolutions,byprovidingasolidbackboneforyourenterpriseinformationsystem.PEtALSisbasedonESBfordataexchange.PEtALShasastrongfocusondistributionandclusteringbybasingitsmessageexchangemiddlewareonJORAM(anopen-sourceJMSimplementation).
ChainBuilderChainBuilderisJBI-compliantwiththeadvantagethatithides
thecomplexitiesofJBIbehindaGUI.TheseGUIcapabilitiesandconfigurationeditorsenablesthepoint-and-clickmappingofnon-XMLformattedmessagessuchasvariable,fixed,andX12EDIformats.TheGUIhasanEclipse-basedplug-in,whichwillenabledrag-and-dropfunctionalityforESBcomponentsthroughwizards.
InstallingServiceMixIagreethatweneedtostartdoing,ratherthanreading.ThissectionisintendedtohelpthereadergetstartedwithServiceMix.Wewilltryoutfewexampleswithoutlookingmuchintotherationalebehinddoingso,sincethesamehasbeencoveredthroughotherchapters.Moreover,asingle"GettingStarted"sectionaloneisnotsufficienttohelpareadernewtoESBtoappreciateallaspectsofit;hence,wewillnotattemptthatinthischapteralone.
Therearemultiplewaystogetstartedbutobviouslydeveloperslikeushavetocodesomething,build,deploy,andgetthatrunningwithouttoomuchhassle.Thatisexactlywhatwewilldointhissection.Let'sdothatnow.
HardwareRequirementsAsofServiceMix3.0.x,weneedthefollowingminimumhardware:
31MBoffreediskspacefortheServiceMix3.0.xbinarydistribution
OSRequirementsThefollowingflavorsofServiceMixinstallsareavailable:
Windows:WindowsXPSP2,Windows2000
Unix:UbuntuLinux,PowerdogLinux,MacOS,AIX,HP-UX,Solaris,oranyUnixplatformthatsupportsJava
Run-timeEnvironmentServiceMixrequirethefollowingrun-timeenvironmentsettings:
JavaDeveloperKit(JDK)1.6.x(http://java.sun.com/javase/downloads/index.jsp).
TheJAVA_HOMEenvironmentvariablemustbesettotheparentdirectorywheretheJDKisinstalled.
Forexample,C:\Yourfilepath\jdk.1.6.0_04.
ApacheAntand/orMaven.
InstallingServiceMixinWindowsThestepsforinstallingServiceMixinWindowsarelistedasfollows:
ClicktheServiceMix3.1.1ReleaselinkundertheLatestReleasessectionofthedownloadpageavailableathttp://incubator.apache.org/servicemix/download.html.
Downloadthebinarydistributionofyourchoice.Forexample,apache-servicemix-3.1.x.zip;apache-servicemix-3.1.1-
incubatingisthepreferredrelease.
ExtractthisZIPfileintoadirectoryofyourchoice.Itisadvisednottohaveillegalcharactersorblankspacesintheinstallationpathdirectories.
NOTENOTE
Asofthiswriting,apache-servicemix-3.1.1-incubatingisthestablerelease.YoucandownloadthisversionoftheServiceMixbinaryfrom:http://incubator.apache.org/servicemix/servicemix-311.html
InstallingServiceMixinUnixToinstallServiceMixinUnix,followsimilarproceduresasforWindows,exceptdownloadthebinarydistributionwithfilenamesimilartoapache-servicemix-x.x.x.tar.gz.
ConfiguringServiceMixIntheServiceMixinstallationhomedirectory,thereisasub-directorynamedconf.ThishostsallmajorconfigurationfilesforServiceMix.servicemix.propertiesherecontainstheportspecifications,especiallythermi.port.Youcanchangesomethinghere,ifthedefaultportsareengagedorforsomeotherreason.
StartingServiceMixTostartServiceMix,gotoSERVICEMIX_HOME\bin(whereSERVICEMIX_HOMEistheparentdirectorywhereyouhaveextractedthebinaryZIP)andthenexecuteservicemix.bat.Now,ServiceMixisrunningwithabasicconfiguration,butnocomponents.
WhilestartingServiceMix,workingdirectoriesgetcreated
relativetothecurrentdirectoryfromwhereyouarestartingServiceMix.
StoppingServiceMixForbothWindowsandUnixinstallations,youcanterminateServiceMixbytypingCTRL-CinthecommandshellorconsoleinwhichServiceMixisstarted.
ResolvingclasspathIssuesWhenweexpandthebinaryZIPfolderofServiceMixinstallation,alltherequiredlibrariesarenotextractedandincludedinthecorrectfolder.InServiceMix,therequiredJavalibrariesshouldbeplacedinSERVICEMIX_HOME\liborSERVICEMIX_HOME\lib\optionalfolder.Soanymissinglibrariescanbeaddedtothesetwofolders.SomelibrariesarealreadyavailableinSERVICEMIX_HOME\componentsorSERVICEMIX_HOME\components\libfolder,andwecanextractthelibrariesfromtheseplacestoSERVICEMIX_HOME\liborSERVICEMIX_HOME\lib\optionalfoldersasandwhenrequired.
ThefollowingarethetwomostcommonerrorsthathappenwhenstartingServiceMixandtherequiredlibrariesarenotfoundinthecorrectplace:
Causedby:java.lang.ClassNotFoundException:…
Causedby:
org.springframework.beans.factory.BeanDefinitionSto
reException:Unrecognizedxbeannamespacemapping:…
Itisveryimportantthatwheneitheroftheaboveerrorsorsomesimilar"librariesnotfound"errorhappens,youeitherfollowwhatwehavealreadyexplainedordownloadanydependentlibrary(.jarfiles)fromthird-partywebsites,andplacethemintheSERVICEMIX_HOME\liborSERVICEMIX_HOME\lib\optionalfolder.
ServiceMixComponents—aSynopsisAsisshownintheServiceMixarchitecturediagram,ServiceMixshipsstandardJBIcomponentsandlightweightJBIcomponents.
StandardJBIComponentsServiceMixstandardJBIcomponentsarefullyJBI-compliant,andsupporttheJBIpackaginganddeploymentmodel.Theyareplacedinthefolder%SERVICEMIX_HOME%\components,andthemajorcomponentsarelistedasfollows:
servicemix-bean:FormappingPOJObeanstoJBIexchanges.
servicemix-bpe:BPELenginebasedonaSybasedonationtotheApacheODEproject.
servicemix-camel:CamelprovidesafullsetofEnterpriseIntegrationPatternsbothfromJavacodeandSpringXML.
servicemix-drools:ProvidesintegrationwithDroolsrulesengine.
servicemix-eip:ProvidesEnterpriseIntegrationPatterns.
servicemix-file:ThisbindingcomponentprovidesintegrationwiththeFilesystem.
servicemix-ftp:AnFTPbindingcomponent.
servicemix-http:AHTTPbindingcomponent.
servicemix-jms:ProvidesintegrationwithmessagingmiddlewarethroughJMS.
servicemix-jsr181:ServiceEnginetoexposeannotatedPOJOsasservices.
servicemix-lwcontainer:Thiscomponentisacontainertowhichwecandeploylightweightcomponents.
servicemix-quartz:ServiceEngineusedtoscheduleandtriggerjobsusingtheQuartzscheduler.
servicemix-saxon:ServiceEngineforintegratingXSLT/XQueryengines.
servicemix-script:HelpstointegratescriptingengineswithJBI.
servicemix-wsn2005:ServiceEngineimplementingOasisWS-Notificationspecification.
servicemix-xmpp:HelpstocommunicatewithXMPP(Jabber)serversthroughtheJBIbus.
LightweightJBIComponentsServiceMixlightweightcomponentsarenotpackagedanddeployedasperJBIspecification.ThisisbecausethecomponentsusedherearelightweightcomponentsthatactivateasingleJBIendpointandtheydonotsupportJBI
deployments.Instead,theycanbeconfiguredusingtheSpringconfiguration.
Listedasfollowsarethemajorlightweightcomponents:
Cache:Cachecomponentcancacheserviceinvocationstoavoidunnecessaryload.
Componenthelperclasses:ThesecomponentsmakeiteasytowritenewJBIcomponents.
Drools:Droolscanbeusedtodorules-basedrouting.
Email:ProvidessupportforMIMEemailsending.
File:Itcanwritemessagestofilesinadirectory,orpollfiles,ordirectoriestosendmessagestoJBI.
FTP:ProvidesintegrationtoFTPviatheJakartaCommonsNetlibrary.
Groovy:HelpstouseGroovyscriptsasendpoints,transformers,orservices.
HTTP:HelpstoinvokerequestsonremoteHTTPserversandtoexposeJBIcomponentsoverHTTP.
Jabber:CanintegratewithJabbernetworkviatheXMPPprotocol.
JAXWS:UsestheJavaAPIforXML-basedwebservicestoinvokeawebserviceortohostaJava-basedwebserviceandexposeitovermultipleprotocols.
JCA:Providesaveryefficientwayofthreadpooling,transactionhandling,andconsumptiononJMSandotherresourceadapters.
JMS:HelpstosendandreceiveJMSmessages.
Quartz:UsedtoscheduleandtriggerjobsusingtheQuartzscheduler.
Reflection:ForIn-OnlyandIn-OutJBIcomponents,wecancreatedynamicproxies,whichwheninvokeddispatchthemessagesintotheJBIcontainer.
RSS:SupportsRSSandAtomviatheRomelibrary.
SAAJ:ProvidesintegrationwithSOAPwithattachmentsforJava(SAAJ)andApacheAxis.
Scripting:HelpstoscriptIn-OnlyorIn-OutmessageexchangesusingaJSR
223compliantscriptingenginesuchasJavaScript,Jython,orGroovy.
Validation:UsedtovalidatedocumentschemausingJAXP1.3andXMLSchemaorRelaxNG.
VFS:Providesintegrationwithfilesystems,jars/zips/bzip2,temporaryfiles,Samba(CIFS),WebDAV,HTTP,HTTPS,FTP,andSFTP.
WSIF:Providesawaytocallwebservices,hidingthedetailsofhowtheserviceisprovided.
XFire:ProvidesintegrationwithXFireSOAPstack.
XSLT:CandoXSLTtransformationforonenormalizedmessagetoanother.
XSQL:UseOracletoolforturningSQLqueriesintoXMLandfortakingXMLandinsertingorupdatingintoadatabase.
Theabovelistsarenotexhaustive,andthenumberofcomponentsaddedtothelistisincreasingdaybyday.ReadersareadvisedtorefertotheServiceMixwebsiteforupdatedinformation.WewilllookatafewamongsttheabovestandardandlightweightJBIcomponentsinsamplesorotherwise,aswewalkthroughdifferentchaptersinthistext.
YourFirstJBISample—BindinganExternalHTTPServiceIhopeallreaders,whethernoviceorprofessional,canunderstandandappreciatewhatwemeanbysayingaHTTPservice,otherwisemostprobablytheywillnotbereadingatextbooklikethis.Hence,IwillchooseaHTTPservicefordemonstrationpurposeshere.
Servlet-basedHTTPServiceAHTTPserviceisanetworkserviceaccessiblethroughtheHTTPprotocol.ServletsarethesimplestcomponentsavailableinJavawithwhichwecanbuildHTTPservice,andhencewewillusethathere.AssumingthatthereaderisfamiliarwithservletsandhowtodeployaHTTPserviceintheirfavoritewebcontainersuchasTomcat,onlythemajorstepsarelistedhere.Forfurtherdetailsthereaderisencouragedtorefertoanyavailableservlettechnologybooks.
Asthefirststep,wewillbuildanddeployaverysimpleservlet.Theservletcodeisgivenasfollows:
publicclassWelcomeServletextendsHttpServlet
{
publicstaticfinalStringXML_CONTENT="<?xml
version=\"1.0\"?><Name>Binil'sServletwishes
you</Name>";
publicvoidinit(ServletConfigconfig)throws
ServletException
{
super.init(config);
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,IOException
{
doPost(request,response);
}
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,IOException
{
System.out.println("WelcomeServlet.doPost...");
response.setContentType("text/xml");
response.setContentLength(XML_CONTENT.length());
response.setContentLength(XML_CONTENT.length());
PrintWriterout=response.getWriter();
out.println(XML_CONTENT);
out.flush();
}
}
Asshowninthecode,theservletsimplyspitsoutsomeXMLcontenttotheresponsestream,withoutevenlookingatthecontentsoftherequest.Equallysimpleistheweb.xmlfileanditisalsoshownhere:
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<web-app>
<display-name>WAPExamples</display-name>
<description>WAPExamples.</description>
<servlet>
<servlet-name>WelcomeServlet</servlet-name>
<servlet-class>
com.binildas.esb.servicemix.servlet.WelcomeServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WelcomeServlet</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
</web-app>
Asafirststep,ifyouhaven'tdoneitbefore,editexamples.PROPERTIES(providedalongwiththecodedownloadforthischapter),andchangethepathstheretomatchyourdevelopmentenvironment.
Nowtobuildthewebcomponent,changethedirectoryto
ch03\Servletandexecuteantscript.
cdch03\Servlet
ant
Here,weassumethatyouhaveinstalledthelatestversionofApacheAntbuildtoolandthebinfolderofthatisinyourpathenvironmentvariable.Thiswillgeneratethewebarchive(EsbServlet.war)andplaceitinthedistfolderinsidech03\ServletwhichcanbedeployedinthewebappsfolderofTomcat(oranyotherrelevantwebserver)andrestarttheserver.
TheHTTPservicewouldhavebeenexposedbynowandthesamecanbeaccessedusingyourfavoritebrowserwiththefollowingURL:
http://localhost:8080/EsbServlet/hello/
WecannowwriteClientcodesimilartowhatisshowninthefollowingcodetotesttheHTTPservice:
publicclassHttpInOutClient
{
privatestaticStringurl=
"http://localhost:8080/EsbServlet/hello/";
privatestaticStringfileUrl=
"HttpSoapRequest.xml";
protectedvoidexecuteClient()throwsException
{
InputStreaminputStream=
ClassLoader.getSystemResourceAsStream(fileUrl);
byte[]bytes=newbyte[inputStream.available()];
inputStream.read(bytes);
inputStream.read(bytes);
inputStream.close();
URLConnectionconnection=new
URL(url).openConnection();
connection.setDoOutput(true);
OutputStreamos=connection.getOutputStream();
os.write(newString(bytes).getBytes());
os.close();
BufferedReaderin=newBufferedReader(new
InputStreamReader(connection.getInputStream()));
StringinputLine;
while((inputLine=in.readLine())!=null)
{
System.out.println(inputLine);
}
in.close();
}
publicstaticvoidmain(String[]args)throws
Exception
{
if(args.length==2)
{
url=args[0];
fileUrl=args[1];
}
HttpInOutClienthttpInOutClient=new
HttpInOutClient();
httpInOutClient.executeClient();
}
}
NotethatwearetestingtheHTTPservicebysendingarbitraryXMLcontentasarequest,eventhough,anycharacterstreamwillbeacceptableasrequest.Thisisbecause,laterwewillbindthisservicetotheServiceMixESBandduringthattimemessageshavetoberoutedthroughtheNMR.Forthis,XMListhevalidnormalizedmessage.
Toruntheaboveclient,makesure(edit,ifrequired)theruntargetinthech03\Servlet\build.xmlfilematchesthefollowingcode:
<targetname="run">
<javaclassname="HttpInOutClient"fork="yes"
failonerror="true">
<classpathrefid="classpath">
<argvalue="
http:/localhost:8080/EsbServlet/hello/">
<argvalue="HttpSoapRequest.xml">
</java>
</target>
Now,executingantrunwillsendamessagetotheHTTPservice:
cdch03\Servlet
antrun
ConfiguretheHTTPServiceinServiceMixBeforeIstartdescribingthebindingofservicestoServiceMix,Iwouldliketoputoutonewordofcaution—thebindingcomponentsusedinthischapterareServiceMixlightweightcomponents.Theyaredeprecatedasofnow,andhenceforanyproductionconfigurationswehavetousestandardJBIcomponents,whichwillbecoveredindetailinsubsequentchapters.StillIamusingthesecomponentsbecausetheyare
simple,straightforward,intuitiveenough,andeasytoconfigureforanoviceuser.
AlltheServiceMixspecificbindingsaredoneinch03\HttpBinding\servicemix.xmlandletuslookstraightintothatinthefollowing:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns="http://xbean.org/schemas/spring/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:lb="http://servicemix.apache.org/demos/gettingstarted">
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.
config.PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<importresource="classpath:activemq.xml">
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<sm:containername="jbi"
monitorInstallationDirectory="false"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpeccomponentName="trace"
service="lb:trace">
<sm:component>
<beanxmlns="http:/xbean.org/schemas/spring/1.0"
class="org.apache.servicemix.components.util.
TraceComponent">
<sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="timer"
service="lb:timer"
destinationService="lb:httpGetData">
<sm:component>
<bean
class="org.apache.servicemix.components.quartz.
QuartzComponent">
<propertyname="triggers">
<map>
<entry>
<key>
<beanclass="org.quartz.SimpleTrigger">
<propertyname="repeatInterval"value="5000"/>
<propertyname="repeatCount"value="0">
<bean>
</key>
<beanclass="org.quartz.JobDetail">
<propertyname="name"value="MyExampleJob"/>
<propertyname="group"value="ServiceMix">
<bean>
</entry>
</map>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="httpGetData"
service="lb:httpGetData"
destinationService="lb:trace">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="org.apache.servicemix.
components.http.HttpInvoker">
<propertyname="url"
value="http://localhost:8080/EsbServlet/hello/">
<bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="httpReceiver"
service="lb:httpReceiver"endpoint="httpReceiver"
destinationService="lb:httpGetData">
<sm:component>
<beanclass="org.apache.servicemix.
components.http.HttpConnector">
<propertyname="host"value="127.0.0.1"/>
<propertyname="port"value="8912">
<bean>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
</beans>
Letusnotlookatthecomplexitiesoftheaboveconfigurationuntillweactuallyruntheservice.Sowewilldeferdiscussionontheabovecodeuntillweseethecodeinaction.
RunServiceMixBasicJBIContainerBeforewebringupServiceMix,yourwebservershouldbeupandrunningwiththewebapplicationgeneratedintheprevioussectiondeployedsuccessfully.
WenowneedtoprepareServiceMixwithafewextralibraries.Forthat,dothefollowing:
Copy%SERVICEMIX_HOME%\components\lib\servicemix-components-3.1.1-incubating.jarto%SERVICEMIX_HOME%\lib\optional.
Open%SERVICEMIX_HOME%\components\servicemix-http-3.1.1-incubating-installer.zipandcopythefollowing.jarsto%SERVICEMIX_HOME%\lib\optional:
jetty*.jar
commons-codec*.jar
commons-httpclient*.jar
Copyquartz.jarfromtheQuartzdistribution(http://www.opensymphony.com/quartz/)to%SERVICEMIX_HOME%\lib\optional.
Now,togetServiceMixupwithcomponentsconfiguredintheXMLconfigurationshownabove,changedirectorytoch03\HttpBinding\andexecute%SERVICEMIX_HOME%\bin\servicemix
servicemix.xml.
WhatyouseeinthefollowingscreenshotisthecontentsofmyServiceMixconsole:
ThefirstpartoftheconsoleoutputisshowingServiceMixinitializingthecomponents,whichwehaveconfiguredpreviouslyinservicemix.xml.Thecomponentsbeinginitialized,inourcase,includetrace,timer,httpGetData,andhttpReceiver.Towardsthelatterpartoftheoutput,wecanseesomeXMLmessages.Infact,whatwehavedoneherebybringingServiceMixupis,wehavetriggeredamessageflowthroughvariouscomponentsconfiguredtotheexternalHTTPservice(inTomcatorso),retrievedtheXMLmessageandsenttotheconsoleoutput.
YouhavesuccessfullyinvokedanexternalHTTPservicethroughServiceMixESB!
RunaClientagainstServiceMixYoucanrepeatsendingmessagesthroughServiceMixESBbyrunningtheclientcodepackagedinthewebapplicationcodebase.Todothis,changethedirectorytoch03\Servlet.
ToruntheclientcodeagainstServiceMix,makesure(edit,ifrequired)theruntargetinthech03\Servlet\build.xmlisasshowninthefollowingcode:
<targetname="run">
<javaclassname="HttpInOutClient"fork="yes"
failonerror="true">
<classpathrefid="classpath">
<arg
value="http:/localhost:8912/EsbServlet/hello/">
<argvalue="HttpSoapRequest.xml">
</java>
</target>
Now,executingthefollowingcommandwillsendanothermessagethroughServiceMixESBtotheHTTPservice.
antrun
WhatJustHappenedinServiceMixThefollowingfigureshowshowweconfiguredvariouscomponentstotheServiceMixESBinservicemix.xml:
Asweknow,allmessageexchangehappensthroughtheNMR.Thedescriptionofvariouscomponentsfollows:
httpReceiver:Here,weconfigureorg.apache.servicemix.components.http.HttpConnector
classtolistentoaparticularport(8912inourcase),connectedtotheNMRusingaHTTPchannel.Thismeansanexternalclient(suchasHttpInOutClientinourcase)cansendHTTPrequeststotheNMRthroughthiscomponent.
httpGetData:org.apache.servicemix.components.http.HttpInvoker
performsHTTPclientinvocationsonaremoteHTTPsite.Asdescribedearlier,wehaveEsbServlet.wardeploymentcontainingWelcomeServletprovidingHTTPserviceintheremotesite.Thus,ineffecttheHttpInvokerfunctionsasabindingcomponentfortheremoteservice.
timer:org.apache.servicemix.components.quartz.QuartzCompo
nentisaQuartzcomponentfortriggeringcomponentswhentimereventsfire.Inourcase,wehaveconfiguredrepeatCountpropertywithavalueofzero,whichmeansthetriggerwillhappenonlyonce.
trace:org.apache.servicemix.components.util.TraceComponen
tisasimpletracingcomponent,whichcanbeplacedinsideapipelinetotracethemessageexchangethoughthecomponent.
Obviously,therearemultiplepathswhichwecandefineusingvariouscombinationsofthesecomponents.Wehaveconfiguredatypicaloneinservicemix.xmlsoastoenabletheclienttosendmessagesthroughthispipelinetotheremoteHTTPservice.WhentheclientsendsamessagetotheServiceMixESB,itreachestheNMRthroughthehttpReceivercomponent.ThedestinationServiceforhttpReceiverishttpGetData,hencethemessageisroutedtohttpGetData.However,httpGetDataisaninvokertotheremoteHTTPService.ThisendsupininvokingtheremoteHTTPservicepassingthemessageparameters.Theservicegetsinvokedandanyresponseisroutedbackthroughasimilarpipelinebacktotheclient.
SpringXMLConfigurationforServiceMixServiceMixusesXMLconfigurationfiles.From2.0onwards,ServiceMixusetheXBeanlibrarytodotheXMLconfiguration.Thus,thesimplestwaytostartusingServiceMixtowiretogetherJBIcomponentsisviaSpringandtheXMLconfigurationfilemechanismfromSpring.
Wewillnowlookatthedetailsofhowwehaveconfiguredcomponentstogether.First,weintroduceafewnewXMLtagsforJBIconfigurationsuchascontainerandactivationSpecs,butapartfromthat,youcanusealltheregularSpringconfigurationtags—beans,bean,property,andvalue.Forexample,insidethe<component>tagyoucanconfigurepropertiesonthe
component.Acomponentcanhave<bean>tagwithnested<bean>tagandsoon.ThisallowsyoutomixandmatchregularSpringconfigurationofPOJOswiththeServiceMixJBISpringconfigurationmechanism.
ThetableshowninthefollowinglistsoutafewkeyattributedetailsfortheJBIcontainerelement.TheServiceMixwebsitewillgivedetailsontheelementsandattributeswhicharenotdescribedhere.AlsothebeanwiringdetailsinSpringstyleandall,arenotdescribedhere,sinceweassumethatthereaderisfamiliarwiththat.Ifnot,anyothertextbookonSpringwillhelpyouhere.
Sr.No.
KeyAttributeName
AttributeType
Description
1
name
String
DenotesnameoftheJBIcontainer.Thishastobeuniqueifitisrunninginaclusterconfiguration.ThedefaultnameisdefaultJBI
2
useMBeanServer
Boolean
Ifsettotrue,ServiceMixwilltrytofindanMBeanServerfromtheMBeanServerFactoryifoneisnotsupplied
3
create
Bool
Ifsettotrue,ServiceMixwillcreateit'sown
3
createMBeanServer
Boolean
Ifsettotrue,ServiceMixwillcreateit'sownMBeanServerifoneisnotsuppliedtothecontainerorfoundfromanMBeanServerFactory
4
rmiPort
Int
Thisistheportusedforthermiregistry(andthus,theJMXconnector)andthedefaultisto1099.
TheServiceMixcomponentmaybegivenfollowingnames:
ComponentName
Service
Endpoint
DestinationService
Wemayalsousethefollowinginacomponenttospecifyitsrouting:
destinationService
destinationInterface
destinationOperation
ThePropertyPlaceholderConfigurerreadsSERVICEMIX_HOME\conf\servicemix.properties
file,whichcontainsvaluesforcommonlyusedenvironmententriessuchasrmi.portorjmx.url.
Aswelookintomoresamplesinsubsequentchapters,youwillbetterunderstandthemechanismofwiringservicesintheJBIbusandhowwecanroutemessagesthroughtheseservices.
SummaryJustlikeanEJBcomponentlivesinanEJBcontainer,aJBIcomponentlivesinaJBIcontainer.AJBIcontainerprovideshostingfacilitiesforaJBIcomponentandcontrolthelifecycleofthecomponent.MultiplevendorsprovidetheirownimplementationsoftheJBIcontainer.
ServiceMixistheonewehaveseenhereindetail,whichwewillbecontinuinginthisbookforthepurposeofshowingJBIusingexamples.JustlikethescenarioyouhavealreadyseeninthischapterofbindinganexternalHTTPservicetotheJBIcontainer,wecanalsobindmanyotherprotocolsandformattedcomponentstotheJBIcontainer,thusprovidingaServiceWorkbenchattheJBIcontainer-level.However,theinterestingparttobenotedisthatevenbeforeJBI,wehavebeendoingbindingandintegrationofdifferentkindsofservicesinmultipleways.
Thenextchapterisdevotedtore-lookathowwehavebeendoingthings,withoutafullfledgedJBIcontainer.ThiswillhelpyoutogetabroaderpictureoftheasisstateofJBI;fromtherewewilldigmoreintoJBIandrelatedservices.
Chapter4.Binding—TheConventionalWayBindingserviceslocallyorremotelyisnotaninnovationbroughtbyESBorJBI,butwehavebeendoingitinmultiplewaysallthroughtheyears.Inthischapter,wewillexplorethemeaningof"Binding"andthenlookathowwecanbindaremotelyavailableservice(intheformofanEJBcomponent)toamiddle-tierandexposeitthroughafirewallfriendlychannellikeHTTP.Bytheendofthechapter,youwillappreciatehowanextraindirectionwithasuitabletunnelingwillhelptoexposeeventechnologyspecificAPIservices,sothattheservicebecomestechnologyagonistic.
Wewillcoverthefollowinginthischapter:
Meaningofbinding
ApacheSOAPbinding
BindingastatelessEJBservicetoApacheSOAP
Runningthesample
Binding—WhatitMeansWewillconsidertheverybasicrequirementoftwoapplicationsortwoservicesinteracting—toexchangemessages.Applicationssharedataintheformofmessages.
Oneoftheapplicationssendsmessageswhiletheotherreceivesit.Messagesareexchangedbetweenasenderapplicationandareceiverapplicationoveramessagingchannel.Letuslookatbindinginthiscontext.
BindingApplicationsconnecttothemessagingchannelthroughamessageEndpoint.TheprocessofconnectinganapplicationorservicetoasuitableEndpointiscalled'binding'.Inmoretechnicalterms,abindingwilldefinehowPortType(abstractinterfaceoftheservice)isboundtoaparticulartransportprotocolandanencodingschema.Abindinginteractioninvolvesaservicerequesterandprovider.Whenanapplicationusestheservicedescriptiontocreateamessagetobesenttotheserviceprovider,wearebindingtotheservice.
EndpointsSincemultipleapplicationsorservicesinteractwitheachotherthroughamessagingchannel,theyhavetodealwithmultipletransportmechanismsandmessageformats.Endpointsdothefunctionalityofconvertingmessagesfromoneformatto
another.Thustherestoftheapplicationknowslittleaboutmessageformats,messagingchannels,oranyotherdetailsofcommunicatingwithotherapplicationswhentheyexchangemessages.Sinceendpointsdothismessagenormalizationfunctionality,amessageendpointcodeiscustomtoboththeapplicationandthemessagingsystem'sclientAPI.
WhenwewriteaprogramtoamessagingAPIsuchasJMS,we'redevelopingendpointcode.Thisinvolveseitherdevelopinglow-levelplumbingcodebyhandorusingappropriateclientAPIsandrun-timetoolstoautomaticallygeneratecode.Later,wewillseethatawholelotofendpointsareavailable,asofftheshelfcomponentsalongwithmessagebusproductslikeServiceMix.Inthischapter,wewilllookatrawformsofbindingservice.Thisexamplehelpustounderstandwhatweactuallymeanbybinding.
ApacheSOAPBindingAssaidearlier,withoutusingaJBIoranESBframework,letusseebindinginactionusingtheApacheopen-sourceSOAPstack.
AWordaboutApacheSOAPApacheSOAPisanimplementationbasedontheSOAPsubmissiontoW3C(WorldWideWebConsortium).ThissubmissionhasbeenproducedbytheXMLProtocolWorkingGroup,whichispartoftheWebServicesActivity.IBM
AlphaworksfirstbroughtaJavareferenceimplementationoftheSOAP1.1specification,whichiscontributedtoformtheApacheSOAPproject.
SOAPisalightweightprotocolfortheexchangeofinformationinadecentralized,distributedenvironment.SOAPisbasedonXMLandconsistsofthreeparts—anenvelope(containingandoptionalHeaderandamandatoryBody)thatdefinesaframeworkfordescribingwhatisinamessageandhowtoprocessit,asetofencodingrulesforexpressinginstancesofapplication-defineddatatypes,andaconventionforrepresentingremoteprocedurecallsandresponses.
ApacheSOAPFormatandTransportsApacheSOAPsupportsthreeencodingstyles:
1. XMIencoding:This(availablewhenusingJava1.2.2)providessupportforautomaticmarshallingandunmarshallingofarbitraryobjects.
2. SOAPencoding:Built-insupportisprovidedforencoding/decodingprimitivetypeslikeStringsandInteger,arbitraryJavaBeans(usingreflection)andone-dimensionalarraysofthesetypes.Forothertypes,theusercanhandwriteencoders/decodersandregisterwiththeXMLSOAPruntime.
3. LiteralXMLencoding:AllowsustosendXMLelements(DOMorg.w3c.dom.Elementobjects)asparametersbyembeddingtheliteralXMLserializationoftheDOMtree.
ApacheSOAPsupportsmessagingandRPCovertwotransports—HTTPandSMTP.AspertheSOAPspecification,
allSOAPimplementationsshouldsupportSOAPXMLpayloadoverHTTPTransport.Asoptionalfeatures,implementationsarefreetosupportothertransportbindingslikeJMS,FTP,andSMTP.Vendorscanevensupportproprietarytransportbindingsforwhatsoeverreasontheyhave,sothereshouldbenothingwhichpreventsonefromnotexposingXMLSOAPevenoverradiowavesasatransportmechanism!
RPCandMessageOrientedAnApacheSOAPserviceorbindingcanbeRPCormessageoriented.
IfitisRPCoriented,theruntimeexpectsastrict,SOAPformattedrequest(andresponsetoo).TheruntimewillprocesstheSOAPenvelope,dispatchtheRPCmethodcallrequesttotheappropriateserviceimplementationclassandtotheappropriatemethod.ForwardtheresponsebacktotheSOAPclient.
Ifitisamessageoriented,requestandresponse,theyaretransportedinadocumentstyle—wehavefreedomtoembedarbitraryformatsofmessageinsidetheSOAPenvelope.ThatmeanstheruntimewillpassthroughtheSOAPbodytotheserviceimplementation,anditisthedutyoftheserviceimplementationtoprocessthecontentsoftheSOAPEnvelope.
BindingServices
ApacheSOAPutilizesdeploymentdescriptorsintheformofXMLfilestoprovideinformationtotheSOAPruntimeabouttheservicesthatshouldbemadeavailabletoclients.TheycanprovideawidearrayofinformationsuchastheUniformResourceNames(URN)fortheservice(whichisusedtoroutetherequestwhenitcomesin),methodandclassdetails,iftheserviceisbeingprovidedbyaJavaclassorthemethod.Moreover,theEJBJNDIname,iftheserviceisbeingprovidedbyanEJB.TheexactcontentsofthedeploymentdescriptordependuponthetypeofartifactwhichisbeingexposedviaSOAP.
NOTENOTE
URNsareintendedtoserveaspersistent,location-independentresourceidentifiers
ApacheSOAPsupportsthefollowingartifactsasservicestobeboundtotheruntime:
StandardJavaclasses
EJBs
BeanScriptingFramework(BSF)supportedscript
Theserviceelementistherootelementofthedeploymentdescriptorandisshowninthefollowingcode:
<isd:service
xmlns:isd="http://xml.apache.org/xmlsoap/deployment"
id="urn:ejbhello">
<!--othercodegoeshere-->
</isd:service>
Theserviceelementcontainsanidattributewhichisusedtospecifythenameoftheservice.SOAPclientsusethevalueoftheidattributetorouterequeststotheservice.WewillusetheURNsyntaxtospecifythenameoftheserviceasurn:ejbhello.TheserviceelementcanalsocontainanoptionaltypeandanoptionalcheckMustUnderstandsattribute.
TheoptionalcheckMustUnderstandswillmandatewhethertheservershouldunderstandaparticularSOAPheaderinthemessage.Ifthereceivercannotrecognizetheelement,itmustfailwhenprocessingtheheader.TheserverwillthrowaSOAPfault,ifthereareSOAPheadersinaSOAPrequestmessagethathavethemustUnderstandattributesettotrue.
Theproviderelementisthemostimportantelementwhichcontainsattributesandsub-elementsthatspecifythedetailsoftheartifactthatisimplementingtheservice.Theproviderelement,attributes,andsub-elementsareshowninthefollowingcode:
<isd:providertype="org.apache.soap.providers.
StatelessEJBProvider"scope="Application"
methods="hello">
<isd:optionkey="JNDIName"
value="sample-statelessSession-TraderHome">
<isd:optionkey="FullHomeInterfaceName"
value="samples.HelloServiceHome">
<isd:optionkey="ContextProviderURL"
value="t3://localhost:7001">
<isd:optionkey="FullContextFactoryName"
value="weblogic.jndi.WLInitialContextFactory">
</isd:provider>
Thetypeattributeoftheproviderelementtellstheruntimewhichproviderimplementationhastobeusedatruntime.Theavailableprovidersare:
java
script
org.apache.soap.providers.StatelessEJBProvider
org.apache.soap.providers.StatefulEJBProvider
org.apache.soap.providers.EntityEJBProvider
Thenestedelementswithintheproviderelementsarespecifictothetypeofartifactusedtodefinetheserviceandareselfexplanatory.
SampleBindaStatelessEJBServicetoApacheSOAPInthissection,wewillwalkthroughasamplebindingscenariowhichwillhelpustounderstandbindingofservices.
SampleScenarioThesamplewillmakeuseofthefollowingrun-timesetups:
ApacheSOAPinTomcat
EJBcontainerinBEAWeblogic
AstatelesssessionEJB(HelloServiceBean)isdeployedinBEAWeblogicServerwhichexposesasinglemethod,shownasfollows:
publicStringhello(Stringphrase)
HelloServiceBeanexposesanEndpoint.ThisEndpointconnectstoaWeblogicspecifict3channel.t3channelcanpassthrought3protocol,forobjectserviceaccess.LetusassumethatwehavearequirementofaccessingtheaboveEJBservicethroughaHTTPchannel(forsomereasonlikeafirewallrestrictionbetweentheserverandtheclient).Wecansolvethisproblembymakinguseofawebserverinfrastructure.
Eventhoughwecanusedifferentwebserversetups(evenWeblogic'swebcontainercanbeusedforthis)toachievethis,wewilluseApacheTomcatforourdemo.TomcatwillhostApacheSOAPasaninternalwebapplication.WewillcreateaservicebindinginsidetheApacheSOAPruntimeinTomcattobindtheEJBservice.Thismeans,wecanchainaHTTPchannelusingasuitablebindingtothet3channel.DoingsowillallowclientstospeaktheHTTPlanguagetoservicebindinginTomcatthroughHTTPchannel,andTomcatwillinturntranslatetheHTTPprotocoltot3protocolandpassthroughthemessagetothet3channel.SothatthemessagewillultimatelyreachtheEJBcomponenthostedinWeblogicapplicationserver.
Theentirescenarioisrepresentedinthefollowingfigure:
Thedeploymentforthesamplerequirementwilltranslatetothatshowninthefollowingfigure:
CodeListingInthissection,wewillwalkthroughthemaincodeusedforthedemo.Allthecodediscussedhereisinthefolderch04\AxisSoapBindEjb:
SessionEJB:TheHelloServiceBean.javaclassisshownhere:
publicclassHelloServiceBeanimplements
SessionBean
{
publicStringhello(Stringphrase)
{
System.out.println("HelloServiceBean.hello{"
+(++times)+"}...");
return"FromHelloServiceBean:HELLO!!You
justsaid:"+phrase;
}
}
TheHelloServiceBean.javaisasimplestatelesssessionEJBandhenceisstraightforward.
<weblogic-ejb-jar>
<weblogic-enterprise-bean>
<ejb-name>statelessSession</ejb-name>
<enable-call-by-reference>True</enable-call-
by-reference>
<jndi-name>sample-statelessSession-
TraderHome</jndi-name>
</weblogic-enterprise-bean>
</weblogic-ejb-jar>
WewilldeploytheEJBinWeblogicserver(eventhoughthesameEJBcanbedeployedinanycompatibleEJBserverlikeWebsphereorJBoss)andhencewerequiretheweblogic-ejb-jar.xmlasshownabove.Themostimportantthingtonotehereisthejndi-namewhosevaluewehaveconfiguredassample-statelessSession-TraderHome.
ApacheSOAPBinding:TheDeploymentDescriptor.xmlcontainsentriesasshowninthefollowingcode:
<?xmlversion="1.0"?>
<isd:service
xmlns:isd="http://xml.apache.org/xmlsoap/deployment"
id="urn:ejbhello">
<isd:provider
type="org.apache.soap.providers.
StatelessEJBProvider"
scope="Application"methods="hello">
<isd:optionkey="JNDIName"
value="sample-statelessSession-TraderHome">
<isd:optionkey="FullHomeInterfaceName"
value="samples.HelloServiceHome">
<isd:optionkey="ContextProviderURL"
value="t3://localhost:7001">
<isd:optionkey="FullContextFactoryName"
value="weblogic.jndi.WLInitialContextFactory"
>
</isd:provider>
<isd:faultListener>
org.apache.soap.server.DOMFaultListener
</isd:faultListener>
</isd:service>
Here,wecannotethatwehavegiventhevaluesample-statelessSession-TraderHomeforthekeyJNDIName.So,herewearereferringtotheEJBservicewedeployedpreviously.Wehaveconfiguredweblogic.jndi.WLInitialContextFactory,whichcancreateinitialcontextsforaccessingtheWebLogicnamingservice.
Wehaveconfiguredorg.apache.soap.providers.StatelessEJBProv
iderforbindingtheEJBservicetospeakSOAPprotocol.StatelessEJBProviderimplementsthetwomethodsdefinedinorg.apache.soap.util.Provider,thatisshowninthefollowingcode:
publicinterfaceProvider
{
publicvoidlocate(DeploymentDescriptordd,
Envelopeenv,Callcall,StringmethodName,
StringtargetObjectURI,SOAPContextreqContext)
throwsSOAPException;
publicvoidinvoke(SOAPContextreq,SOAPContext
res)throwsSOAPException;
}
Aprovider'sfunctionissplitintotwopieces—locatingthe
service(whichalsoincludesanyverificationthattheservicecanbeexecuteatallandbytheclient),andactuallyrunningit.It'suptotheinvokemethodtocalltheactualserviceuptograbandformattheresponseintoaSOAPresponseobject.
Duringinitialization,StatelessEJBProviderwilldothefollowingtogetaremotereferencetotheEJBcomponent:
EJBHomehome=(EJBHome)
PortableRemoteObject.narrow(contxt.
lookup(jndiName),
Class.forName(homeInterfaceName));
MethodcreateMethod=home.getClass().
getMethod("create",newClass[0]);
remoteObjRef=(EJBObject)
createMethod.invoke((Object)home,new
Object[0]);
DuringactualmethodinvocationStatelessEJBProviderwillexecutethefollowingcode:
Methodm=MethodUtils.getMethod(remoteObjRef,
methodName,argTypes);
Beanresult=newBean(m.getReturnType(),
m.invoke(remoteObjRef,args));
RunningtheSampleAsafirststepandifyouhaven'tdoneitbefore,editexamples.PROPERTIESprovidedalongwiththecodedownloadforthischapterandchangethepathstheretomatch
yourdevelopmentenvironment.ThecodedownloadforthischapteralsoincludesaREADME.txtfile,whichgivesdetailedstepstobuildandrunthesamples.
Runningthesampleinvolvesmultiplesteps,asshownasfollows:
DEPLOYINGTHEEJBFordeployingtheEJB,wehavetofollowgeneralEJBdeploymentstepsasspecifiedintheWeblogicdocumentation.
SinceyouarebuildingyourfirstEJBsampleinthisbook,wewillspendalittlemoretimetohelpyoutodeployyourEJBsample.First,changedirectorytotheEJBsamplesdirectory.
cdch04\AxisSoapBindEjb\ejb
Now,settheenvironmentvariablesforthebuildconsoleaspertheWeblogicdocumentationandthenusetheantscriptprovidedalongwiththeWeblogicserverbundle.Forthat,dothefollowing:
%wl.home%\samples\domains\examples\setExamplesEnv
.bat
%wl.home%\server\bin\ant
AssumingthatyouareusingtheWeblogic8.xversion,theabovestepsshouldhavebuilttheEJBbynow.IfyouuseadifferentversionoftheEJBserver,orifyouuseadifferent
vendor'sEJBserver,refertothedocumentationstheretomakechangestothebuildexercise.
WecaneventestwhetherourEJBdeploymentwentfinebyexecutingatestclient,like:
cdch04\AxisSoapBindEjb\ejb
%wl.home%\server\bin\antrun
BINDEJBTOSOAPWewillusetheApacheSOAPimplementationforthisdemonstration.FromtheApacheSOAPdistribution,copythesoap.warfileanddeploythattothewebappsfolderofyourfavoritewebserver(ApacheTomcat).Youalsoneedtocopythefollowingfilesandmakethemavailableinthelibfolderofyourwebserver:
%wl.home%\server\lib\weblogic.jar
%wl.home%\samples\server\examples\build\clientclasses\
sample_statelessSession_client.jar
Nowrestartyourwebserver.
ApacheSOAPprovidesServiceManagerClientusingwhichwecanregistertheremoteEJBbindingtotheSOAPenvironment.Thefollowinganttaskdoesexactlythis:
<targetname="deploy"depends="compile">
<java
classname="org.apache.soap.server.ServiceManagerClient"
fork="true">
<arg
value="http://localhost:8080soapservlet/rpcrouter">
<argvalue="deploy">
<argvalue="DeploymentDescriptor.xml">
<classpath>
<pathrefid="classpath">
</classpath>
</java>
</target>
Thisanttargetcanbeinvokedbytyping:
cdch04\AxisSoapBindEjb\SoapBind
antdeploy
TheServiceManagerClientintheabovedeploytargettakesthreeparameters—theURLtotheSOAPserver,thecommanddeploy,andthefilecontainingyourdeploymentdescriptor.ThefirstparameterspecifiestheURLoftheApacheSOAPRPCrouter,whichwillhelpinroutingclientrequeststotherequestedservice.ThesecondparameterspecifiestheoperationthattheServiceManagerClientshoulddo.Thedeployoperationregisterstheserviceusingthedeploymentinformationlocatedinafilespecifiedbythethirdparameter.Inourcase,thefileiscalledDeploymentDescriptor.xmlanditcontainsthedeploymentdescriptorforthehelloService.
Onceyouhaveexecutedthedeploycommand,youcan
executethelistcommand.Youshouldnowseeoutputlistingurn:ejbhello,whichistheuniqueIDofyourservice.Youcanalsoviewthisservicefromthewebadmintoolbygoingtohttp://localhost:8080soapadmin/index.html
andselectingtheListbutton.Thelistanttargettoexecutethelistcommandisasfollows:
<targetname="list">
<java
classname="org.apache.soap.server.ServiceManagerClient"
fork="true">
<arg
value="http://localhost:8080soapservlet/rpcrouter"/>
<argvalue="list">
<classpath>
<pathrefid="classpath">
</classpath>
</java>
</target>
Wecanverifywhetherthedeploymentwassuccessfulbytypingthefollowing:
antlist
RUNTHECLIENTTheclientcreatesaCall,setsparameters,andinvokestheservicebindingasshowninthefollowingcode:
URLurl=newURL(args[0]);
Callcall=newCall();
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
call.setTargetObjectURI("urn:ejbhello");
call.setMethodName("hello");
Vectorparams=newVector();
params.addElement(newParameter("phrase",
String.class,"what'syourname?",null));
call.setParams(params);
Responseresp=call.invoke(url,"");
Parameterresult=resp.getReturnValue();
Therunanttargetwillexecutetheclientcode.
<targetname="run">
<javaclassname="samples.ejb.SoapTest"
fork="true">
<arg
value="http://localhost:8080soapservlet/rpcrouter">
<classpath>
<pathrefid="classpath">
</classpath>
</java>
</target>
Toruntheclient,type:
antrun
WhatJustHappenedIfeverythingwentfine,youwouldseesomethingsimilarto
theresultasshowninthefollowingscreenshot:
TheSoapTesthasactuallycreatedaSOAPrequestandroutedittotheservicebindingwithinSOAPruntime.TheformatofthisSOAPrequestisasfollows:
POSTsoapservlet/rpcrouterHTTP/1.0
Host:localhost:8080
Content-Type:text/xml;charset=utf-8
Content-Length:458
SOAPAction:""
<?xmlversion='1.0'encoding='UTF-8'?>
<SOAP-ENV:Envelopexmlns:SOAP-ENV=
"http://schemas.xmlsoap.orgsoapenvelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema
-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<ns1:helloxmlns:ns1="urn:ejbhello"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.orgsoapencoding/">
<phrasexsi:type="xsd:string">
what'syourname?
</phrase>
</ns1:hello>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
AHTTP-basedSOAPendpointisidentifiedbyaURL.ThisURL,inourcase,intheaboverequestishttp://localhost:8080soapservlet/rpcrouter
.SOAPMethodNameisanoptionalheader,whichuniquelyidentifiesthemethodname.ForHTTPtransport,SOAPmessagesaresentoverPOSTmethod.TheSOAPmessagebodywillcontaintheXMLformattedcontentrequiredfortheSOAPruntimetoinvoketherequestedmethod.
IntheSOAPcontent,therootelementisanelementwhosenamespace-qualifiedtagname(ns1:helloinourcase)matchestheoptionalSOAPMethodNameHTTPheader.ThisredundancyisprovidedtoallowanyHTTPinfrastructureintermediarieslikeproxies,firewalls,webserversoftware,toprocessthecallwithoutparsingXML,atthesametimealsoallowingtheXMLpayloadtostandindependentoftheenclosingHTTPmessage.
Uponreceivingthisrequest,theStatelessEJBProvidercomes
intoaction.theStatelessEJBProviderunmarshallstheSOAPBodycontentandretrievesthemethodparameters.IttheninvokestheEJBservice,whichisremotelyboundtotheSOAPruntime.TheresultsarethenpackagedbacktoaSOAPresponsebodyandsentbacktotheclient.
TheSOAPresponseisshowninthefollowingcode:
HTTP/1.1200OK
Server:Apache-Coyote/1.1
Set-Cookie:
JSESSIONID=929DAB0C201F82C9B3F575C8276692A1;
Path=/soap
Content-Type:text/xml;charset=utf-8
Content-Length:523
Date:Thu,26Oct200608:20:23GMT
Connection:close
<?xmlversion='1.0'encoding='UTF-8'?>
<SOAP-ENV:Envelopexmlns:SOAP-ENV=
http://schemas.xmlsoap.orgsoapenvelope/
xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<ns1:helloResponsexmlns:ns1="urn:ejbhello"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.orgsoapencoding/">
<returnxsi:type="xsd:string">
FromHelloServiceBean:
HELLO!!Youjustsaid:what'syourname?
</return>
</ns1:helloResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Asyoucanseeabove,theSOAPresponsedoesn'thaveany
SOAPspecificHTTPheaders.ThepayloadwillcontainanXMLdocumentthatcontainstheresultsoftheoperationinvoked.TheresultswillbeinsideanelementwiththenamematchingthemethodnamesuffixedbyResponse.
HowtheSampleRelatestoServiceMixInthissample,wesawhowtouseconventionaltoolslikeanEJBcontainer,ApacheSOAPtoolkit,andApacheTomcatwebcontainertobindanexternalEJBserviceremotelyintoSOAPruntimeandexposetheserviceoveraHTTPtransportchannel.Later,wewillseethatthesamefunctionalitycanbedonewithoutallthesehasslesanddeploymentsteps,butwithjustfewcomponentconfigurationsinServiceMix.Theideabehindthisexampleistomakethereaderfamiliarwiththetechnicalcasebehindtheneedforservicebindingandalsotoreckonthatservicebindingisnotanewconcept,butsomethingwehavebeendoingforalongtime.
SummaryInthischapter,wediscussedasimplebindingscenariobywhichwecanmakeanEJBserviceaccessibleacrossthefirewalltotheoutsideworld.IfyouhaveanApacheSOAPimplementationwithyou,youcanalsotryoutthesamplesandseetheresults.Similartowhatwedidinthissample,attimesweneedtotunnelorredirectservicesthroughintermediaries
eitherduetoprotocolorformatmismatchesorduetosomeotherreasons.
Alltheseactivitiesareconcernsapartfromyourbusinesslogiccodingandneedtobeaddressedatyourapplicationframework-level.Inthischaptertoo,wehaveperformeditinthesamemanner,butwehavedonealotofstepstoconfigurethewebserverwithApacheSOAP.Later,whenyougothroughtheJBIandESBsamplesyouwillrealizethatthesamefunctionalitycanbeachievedbyselectingandconfiguringsuitableJBIcomponents.
ESBimplementationslikeServiceMixmakeuseofnewgenerationSOAPframeworkswhichbindbinaryservicessuchasEJBandPOJOtotheJBIbustomakeitSOA-compliant.
Inthenextchapter,wewilldelvemoreintosuchaSOAPframeworknamelyXFireandlookatsomeveryusefulmediationfeaturesofit.Inthelaterchapters,wewillleveragesimilarfeaturesfromtheJBIbusstraightaway.
Chapter5.SomeXFireBindingToolsJBIadvocatesthatXMLdatabasedonaWSDLmodelshouldbeflowingthroughtheNMR.Hence,areferencetoanappropriateSOAPframeworkcapableofunderstandingWSDLandgeneratingWSDL-compliantformatteddataisimportantinanyJBIdiscussion.
ServiceMixhasthebestintegrationwithXFire,whichisthenewgenerationJavaSOAPframework.SincetheAPIiseasytouseandsupportsstandards,XFiremakesSOAdevelopmentmucheasierandstraightforward.Itisalsohighlyperformanceoriented,sinceitisbuiltonalowmemoryStAX(StreamingAPIforXML)model.Currently,XFireisavailableinversion2.0underthenameCXF.Inthischapter,wewillnotdiscussanyJBIspecificbindingmethods;insteadwewillconcentrateonXFireandlookathowwecanusethesameforintegrationsolutions.
Onceweappreciatethis,wewillbetterunderstandwhatpartoftheintegrationfunctionalitycanbedoneusingXFirewithintheJBIarchitecture.
Wewillcoverthefollowinginthischapter:
BindinginXFire
WebserviceusingXFireConfigurableServlet
WebserviceusingXFireSpringXFireExporter
WebserviceusingXFireSpringJsr181handler
XFireExportandbindEJB
XFireforlightweightintegration
BindinginXFireInXFireterms,bindingsarewaystomapXMLtoJavaobjects.Currently,XFiresupportsthefollowingbindings:
Aegis:AegisisthedefaultXFirebindingwhichmapsXMLtoPOJOs.ItsupportscodefirstdevelopmentwhereyouwriteyourserviceinPOJOsandAegiswillgeneratetheXMLschemaorWSDLforyou.IthasaflexiblemappingsystemsothatyoucancontrolhowyourPOJOsarebound.
JAXB:JAXBisthereferenceimplementationoftheJAXBspecification.XFireintegrateswithJAXB1.0and2.0.
XMLBeans:XMLBeansisanApacheprojectwhichtakestherichness,features,andschemaofXMLandmapsthesefeaturesasnaturallyaspossibletotheequivalentJavalanguageandtypingconstructs.
Message:TheMessageBindinghasspecialsemanticstoallowyoutoworkwithXMLstreamsandfragmentsveryeasily.TheMessageBindingtakestheXMLStreamReaderfromtherequestandprovidesitdirectlytoyourclasses.
Castor:CastorprovidesmarshallingandunmarshallingofXMLandJavaobjectswhichdoesn'trequirerecompilationoftheJavacodeifthemappingdefinitionchanges.HencesystemswheretheservicelayerisbeingdevelopedindependentlyfromthebusinesslayercanbenefitmuchusingCastor.
Adetaileddescriptionoftheaboveframeworksisbeyondthescopeofthisbook,butweneedtolookatwhatXFirehastoofferandhowthisisgoingtohelpusinbindingservicesand
componentstotheServiceMixESB.
XFireTransportsXFireprovidesmultipletransportchannelsforcommunicationsandisbuiltonanXMLmessaginglayer.Themaintransportmechanismsarelistedasfollows:
HTTP:StandardXMLinSOAPformatoverHTTP
JMS:Asynchronousandreliablewayofsendingmessages
XMPPorJabber:AnasynchronousmessagingmechanismforSOAP
AServiceRegistryisthecentralpartoftheXFiremessaginginfrastructure.Userscansendmessagesthroughanyoftheavailabletransportchannels.ThetransportlooksattheservicebeinginvokedandpassesaMessageContextandservicenameofftotheXFireclass.TheXFireclasslooksuptheservicefromtheServiceRegistryandtheninvokestheappropriatehandler.ThusXFiretransportisresponsibleformanagingincomingandoutgoingcommunicationsusingaparticularwireprotocol,whichisshownasabstractinthemethodsignatureinthefollowingcode:
publicinterfaceTransportextends
ChannelFactory,HandlerSupport
{
BindingfindBinding(MessageContextcontext,
Serviceservice);
}
JSR181andXFireJavaWebServicesMetadata(WSM,basedonJSR181)isbuiltoverJavaLanguageMetadatatechnology(JSR175).TheintentionbehindJSR181istoprovideaneasytousesyntaxfordescribingwebservicesatthesource-code-levelfortheJ2EEplatform.Thus,WSMleveragesthemetadatafacilityinJavatowebservices.Inotherwords,aJavawebserviceisjustaPlainOldJavaObject(POJO)withafewannotations.Theannotationscandescribethewebservicename,detailsaboutthemethodsthatshouldbeexposedinthewebserviceinterface,parameters,theirtypes,thebindings,andothersimilarinformation.XFireiscontinuouslyaddingsupportforJSR181andthischapteralsogivesanintroductiontothis,withworkingexamples.
Wewillwalkthroughfourdifferentbutrelatedworkingsamples.AllofthemdemonstratecapabilitiesofXFire.TheparttonoticeisthesimplicitywithwhichwecangetthingsdonewithXFire.
WebServiceUsingXFireConfigurableServletWebservicesaretoagreatextentinthespiritofSOA.MostwebservicesframeworksinternallyusesaSOAPstackfortransportandformathandling.SinceXFireisaSOAPstackcapableofeasilybuildingwebservices,letuslookintoonesampledoingthathere.
SampleScenarioOuraimhereistoexposeaPOJOaswebserviceusingXFire—org.codehaus.xfire.transport.http.XFireC
onfigurableServlet.
CodeListingXFireConfigurableServletexpectsaservicedefinitionintheformofanxmlfilecalledservices.xml.XFirebyitselfisaweb-basedapplication;hencewearegoingtopackagethesampleapplicationasastandardwebarchive.
Wewillnowlookatthecontentsoftheindividualartifactsthatmakeupthewebarchive:
1. IHello.class:IHelloisasimpleJavainterface,declaringasinglemethodsayHello.
Thisisshowninthefollowingcode:
publicinterfaceIHello
{
StringsayHello(Stringname);
}
2. HelloServiceImpl.class:HelloServiceImplimplementstheIHellointerfaceandhassomeverbosecodeprintingoutdetailsintotheserverconsole.
Thefollowingcodedemonstratesit:
publicclassHelloServiceImplimplements
IHello
{
privatestaticlongtimes=0L;
publicHelloServiceImpl()
{
System.out.println("HelloServiceImpl.HelloServiceImpl()...");
}
publicStringsayHello(Stringname)
{
System.out.println("HelloServiceImpl.sayHello("
+(++times)+")");
return"HelloServiceImpl.sayHello:HELLO!
Youjustsaid:"+name;
}
}
3. services.xml:Herewespecifythedetailsofourwebservices,usingtheserviceClassandimplementationClasselements.serviceClassspecifiestheJavainterface,whichhoststhemethodsignaturewhereasimplementationClassspecifiestheclasswhichimplementsthemethod.AllthemethodsinserviceClasswillbeexposedaswebservices.IftheimplementationClassdoesn'timplementanyinterface,theserviceClasselementcanhavetheimplementationClassitselfasitsvalue.services.xmlisplacedwithintheWEB-INF\classes\META-INF\xfiredirectory,sothatthe
XFireruntimecansetuptheserviceenvironment.ThenameandnamespaceelementscanhaveanyvalidXMLnamesasthevalues.
Itisshowninthefollowingcode:
<beans
xmlns="http://xfire.codehaus.org/config/1.0">
<service>
<name>Hello</name>
<namespace>myHello</namespace>
<serviceClass>IHello</serviceClass>
<implementationClass>HelloServiceImpl</implementationClass>
</service>
</beans>
4. web.xml:Themainpartinweb.xmlisconfiguringtheXFireConfigurableServletasshownhere:
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<web-app>
<servlet>
<servlet-name>XFireServlet</servlet-name>
<display-name>XFireServlet</display-name>
<servlet-class>
org.codehaus.xfire.transport.http.XFireConfigurableServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/servlet/XFireServlet/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>services*</url-pattern>
</servlet-mapping>
</web-app>
AnyrequestofaURLwiththepatternservices*,willberoutedtotheXFireServlet,whichwillinturndothemagicofSOAPhandshaking.
RunningtheSampleAsafirststepandifyouhaven'tdoneitbefore,editexamples.PROPERTIESprovidedalongwiththecodedownloadforthischapter,andchangethepathstheretomatchyourdevelopmentenvironment.Ifyourwebserverdoesn'tincludeXalan(XalanisanXSLTprocessorfortransformingXMLdocuments)libraries,downloadXalanforJava,andtransferxalan*.jarfromthedownloadtothelibrariesfolderofyourwebserver(${tomcat.home}/lib).ThecodedownloadforthischapteralsoincludesaREADME.txtfile,whichgivesdetailedstepstobuildandrunthesamples.
Tobuildthesample,changedirectorytoch05\01_XFireServletWebServiceandexecuteant,asshownhere:
cdch05\01_XFireServletWebService
ant
Thiswillgeneratethewarfile,whichinturncontainsallrequiredlibrariesextractedoutfromtheXFireinstallationfolder.FolderdistwillcontainHelloXFire.war,whichshouldbedeployedinthewebappsfolderofTomcat(oranyotherrelevantwebserver).Now,restarttheserver.
ThewebservicewouldhavebeenexposedbynowandtheservicedefinitioncanbeaccessedusingthefollowingURL:
http://localhost:8080/HelloXFireservicesHe
llo?WSDL
WecannowwriteaClientcodetotestthepreviouswebserviceasshowninthefollowingcode:
publicclassClient
{
privatestaticStringserviceUrl=
"http://localhost:8080/HelloXFireservicesHello";
publicstaticvoidmain(String[]args)throws
Exception
{
if(args.length>0)
{
serviceUrl=args[0];
}
Clientclient=newClient();
client.callWebService("Sowmya"));
}
publicStringcallWebService(Stringname)throws
Exception
{
ServiceserviceModel=new
ObjectServiceFactory().create(IHello.class);
XFirexfire=
XFireFactory.newInstance().getXFire();
XFireProxyFactoryfactory=new
XFireProxyFactory(xfire);
IHelloclient=null;
try
{
client=(IHello)factory.create(serviceModel,
serviceUrl);
}
catch(MalformedURLExceptione)
{
log("WsClient.callWebService():EXCEPTION:"+
e.toString());
}
StringserviceResponse="";
try
{
serviceResponse=client.sayHello(name);
}
catch(Exceptione)
{
log("Client.callWebService():EXCEPTION:"+
e.toString());
serviceResponse=e.toString();
}
returnserviceResponse;
}
}
Attheclientside,weperformthefollowingsteps:
CreateaservicemodelwhichcontainstheservicespecificationfromtheinterfaceIHello.
GetXFireinstanceusingXFireFactory.
RetrieveaproxyfactoryinstanceforXFire.
Usingtheproxyfactory,wecannowgetalocalproxyfortheremotewebserviceusingtheservicemodelandtheserviceendpointURL.
Nowinvoketheremotewebserviceusingtheproxy.
Toruntheclient,assumingthatyouhavealreadycompiledtheclientwhilebuildingthesample,executeantasfollows:
antrun
WebServiceusingXFireSpringXFireExporterHavingseenhowtoexposeaPOJOaswebserviceusingtheXFireclass,org.codehaus.xfire.transport.http.XFireCon
figurableServlet,ournextaimistodothesameusingadifferentapproach.
SampleScenarioHereagain,ouraimistoexposeaPOJOaswebserviceusingXFireSpringsupportclassorg.codehaus.xfire.spring.remoting.XFireEx
porter.Here,theXFireclassXFireExporterisinternallyleveragingSpring'sremotingframeworkandassuchdependsontheSpringlibraries.
CodeListingTheartifactsinthecodelistingisshowninthefollowingfigure:
Wehavefewmoreartifactstobepackagedinthisscenarioandthepackagingtooisslightlydifferentasshownintheabovefigure.Sinceweareusingthesameclasses(IHelloandHelloServiceImpl)asusedinthepreviousexampleheretoo,theyarenotrepeatedhere.Wewilllookattheotherartifactsindetailhere:
1. IHello.class:Thisissameasinthepreviousexample.
2. HelloServiceImpl.class:Thisissameasinthepreviousexample.
3. applicationContext.xml:TheHelloServiceImplclassisconfiguredinSpring'sapplicationContextasshownhere:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans>
<beanid="helloBean"
class="HelloServiceImpl">
<beans>
4. xfire-servlet.xml:Inxfire-servlet.xml,themainpartistheconfigurationofthewebcontrollerthatexportsthespecifiedservicebeanasanXFireSOAPserviceendpoint.Typically,wewilldothisintheservletcontextconfigurationfile.Asgiveninnextsection,sincethedispatcherservletisnamedxfire,thisfileshouldbecalledxfire-servlet.xml.
Thisisshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans>
<beanclass="org.springframework.web.servlet.
handler.SimpleUrlHandlerMapping">
<propertyname="urlMap">
<map>
<entrykey="/HelloService">
<refbean="hello">
<entry>
</map>
</property>
</bean>
<beanid="hello"
class="org.codehaus.xfire.spring.remoting.XFireExporter">
<propertyname="serviceFactory">
<refbean="xfire.serviceFactory">
<property>
<propertyname="xfire">
<refbean="xfire">
<property>
<propertyname="serviceBean">
<refbean="helloBean">
<property>
<propertyname="serviceClass">
<value>IHello</value>
</property>
</bean>
</beans>
1. WehaveconfiguredhelloBeanastheserviceBeanhere.Infact,helloBeaniscomingfromtheapplicationContext.xmlconfiguration.
5. web.xml:Thefeaturetobenotedinweb.xml,istheDispatcherServletconfigurationwhichprovidesthelocationsofwhereyourSpringbeansare.ThecontextConfigLocationtellsSpringwheretofindtheapplicationContext.xmlfiles.
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
WEB-INFapplicationContext.xml
classpath:org/codehaus/xfire/spring/xfire.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>xfire</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>xfire</servlet-name>
<url-pattern>services*</url-pattern>
</servlet-mapping>
</web-app>
RunningtheSampleTobuildthesample,changedirectorytoch05\02_XFireExportWebServiceandexecuteantasfollows:
cdch05\02_XFireExportWebService
ant
Thiswillgeneratethewarfile,whichinturncontainsallrequiredlibrariesextractedoutfromtheXFireinstallationfolder.FolderdistwillcontainHelloXFireExport.warwhichshouldbedeployedinthewebappsfolderofTomcat(oranyotherrelevantwebserver).Now,restarttheserver.
ThewebservicewouldhavebeenexposedbynowandtheservicedefinitioncanbeaccessedusingthefollowingURL:
http://localhost:8080/HelloXFireExportserv
icesHelloService?WSDL
WecannowwriteaClientsimilartowhatwehaveseeninthepreviousexampletotestthewebservice.
Toruntheclient,assumingthatyouhavealreadycompiledtheClient,whilebuildingthesample,executeantasfollows:
antrun
WebServiceUsingXFireSpringJsr181HandlerJSR181definesanannotatedJavasyntaxforprogrammingwebservicesandisbuiltontheJavaLanguageMetadatatechnology(JSR175).Itprovidesaneasytousesyntaxtodescribewebservicesatthesource-code-levelfortheJ2EEplatform.ItaimstomakeiteasyforaJavadevelopertodevelopserverapplicationsthatconformbothtobasicSOAPandWSDLstandards.Inthissample,wewillincreasethecomplexityofthewebservicebyincludingaTransferObject(TO)asaparameter.WewillalsoseeJSR181annotationsworkbehindthescenestogeneratetheplumbingrequiredtoexposewebservices.
SampleScenarioHereagain,ouraimistoexposeaPOJOaswebserviceanduseJSR181annotationsupportforthis.Boththeserviceinterfaceandtheserviceimplementationwillbeannotated.
CodeListingTheartifactsinthecodelistingisshowninthefollowingfigure:
Wewilllistoutthedifferentartifactswhichmakeupthisexampleinthefollowing:
1. IOrder.class:Thisistheserviceinterfaceandiswebserviceannotated.Sinceallmethodsintheinterfacegetexportedbydefault,youdon'tneedtodefinethe@WebMethodannotationintheinterface.Annotationslike@WebResulttoo,aretotallyoptionalandletyoucontrolhowtheWSDL
lookslike.
Theserviceinterface,IOrder.class,isshowninthefollowingcode:
importjavax.jws.WebService;
importjavax.jws.WebResult;
@WebService
publicinterfaceIOrder
{
@WebResult(name="PurchaseOrderType")
publicPurchaseOrderType
getPurchaseOrderType(StringorderId);
}
2. OrderManagerImpl.class:Asyoucanseehere,OrderManagerImplistheserviceimplementationclassandiswebserviceannotated.Weusethe@WebServiceannotationwithsomeparameterslikewebservicenameasthatisusedontheclient-sidetodecoratetheclassandtellthejsr181processorthatthereisaninterfacetoexportthewebservicemethods.
importjavax.jws.WebService;
@WebService(serviceName="OrderService",
endpointInterface="IOrder")
publicclassOrderManagerImplimplements
IOrder
{
publicPurchaseOrderType
getPurchaseOrderType(StringorderId)
{
PurchaseOrderTypepo=new
PurchaseOrderType();
po.setOrderDate(getDate());
USAddressshipTo=createUSAddress("Binil
Das","23HiddenRange","Dallas",
"TX","17601");
USAddressbillTo=createUSAddress("Binil
Das","29KColonialCreast","Mountville",
"PA","17601");
po.setShipTo(shipTo);
po.setBillTo(billTo);
returnpo;
}
}
1. Itisagainworthnotingtheparameterorreturntypehere,sinceitisnolongersimpleJavatype,butacustomclass(complextype).
3. web.xml:Ifyoucomparethisexamplewiththefirstoneinthischapter,youwillnoticethedifferencehere.InsteadofXFireConfigurableServletwearegoingtouseorg.codehaus.xfire.spring.XFireSpringServletasthecontrollerservlet.Thenyouspecifytheurl-patternsothatsuchpatternURLscanberoutedtoXFireSpringServlet.
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<web-app>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:org/codehaus/xfire/spring/xfire.xml,
WEB-INFclasses/META-INF/xfire/xfire-servlet.xml
</param-value>
</context-param>
<servlet>
<servlet-name>XFireServlet</servlet-name>
<servlet-class>
org.codehaus.xfire.spring.XFireSpringServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/servlet/XFireServlet/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>services*</url-pattern>
</servlet-mapping>
</web-app>
4. xfire-servlet.xml:Next,wehavetodefinetheSpringapplicationContextforXFirecalledxfire-servlet.xml.ThemechanismhereistodefineSpring'sSimpleUrlHandlerMappingwhichinturnmakesuseoftheXFireSpringJsr181HandlerMapping.Oncethatisdone,youonlyneedtodefineyourwebservicePOJOsliketheoneseenwiththeidasannotatedOrder.
<?xmlversion="1.0"encoding="UTF-8"?>
<beans>
<beanid="webAnnotations"
class="org.codehaus.xfire.annotations.
jsr181.Jsr181WebAnnotations"/>
<beanid="handlerMapping"
class="org.codehaus.xfire.spring.
remoting.Jsr181HandlerMapping">
<propertyname="typeMappingRegistry">
<refbean="xfire.typeMappingRegistry">
<property>
<propertyname="xfire">
<refbean="xfire">
<property>
<propertyname="webAnnotations">
<refbean="webAnnotations">
<property>
</bean>
<beanid="annotatedOrder"
class="OrderManagerImpl">
<bean
class="org.springframework.web.servlet.handler.
SimpleUrlHandlerMapping">
<propertyname="urlMap">
<map>
<entrykey="">
<refbean="handlerMapping">
<entry>
</map>
</property>
</bean>
<importresource="
classpath:org/codehaus/xfire/spring/xfire.xml">
<beans>
RunningtheSampleTobuildthesample,changedirectorytoch05\03_XFireJsr181BindWebServiceandexecuteantasfollows:
cdch05\03_XFireJsr181BindWebService
ant
Thiswillgeneratethewarfile,whichinturncontainsallrequiredlibrariesextractedoutfromtheXFireinstallationfolder.FolderdistwillcontainXFireJsr181.war,whichshouldbedeployedinthewebappsfolderofTomcat(oranyotherrelevantwebserver).Now,restarttheserver.
ThewebservicewouldhavebeenexposedbynowandtheservicedefinitionofthesamecanbeaccessedusingthefollowingURL:
http://localhost:8080/XFireJsr181servicesO
rderService?WSDL
WecannowwriteaClientsimilartowhatwehaveseeninthepreviousfewexamplestotestthewebservice.
Toruntheclient,assumingthatyouhavealreadycompiledtheClientwhilebuildingthesample,executeantasfollows:
antrun
XFireExportandBindEJBInChapter4,youhavealreadyseenthesampleofhowtoexposeastatelessEJBservicedeployedinanapplicationserver.Hence,theconsumercanusetheSOAPprotocoltoinvoketheEJBservicethroughaHTTPchannel.Letusagaindoasimilardemonstrationhere,butwithXFirenow.OnceyoucompletethisexampleyouwillbetterappreciatethesimilaritybetweenXFiremechanismsandtheprocessofbinding.
SampleScenarioThescenarioistoexposeanEJBcomponentservicetoexternalclientsthroughaHTTPchannel.ThedifferencebetweentheEJBandSOAPsampleinChapter4(Binding—TheConventionalWay)isthatherewewilluseXFireclassesforservicebinding.Also,thethreeprevioussamplesinthis
chapterhavedemonstratedthepowerofXFireinexposingwebservices.Butthissampleismoretowardsbindinganexternalservice,which,asyouwillseeveryshortly,ismoresimilartothebindingactivitywedousingaJBIstack.
CodeListing
Thecodeforthissampleisorganizedintotwo,intwoseparatefolders,onefortheEJBpartandanotherfortheXFirebinding.Wewillwalkthroughthemainclassesonly,inthefollowing:
1. HelloWorldBI.class:HelloWorldBIistheBusinessInterface(BI)classforthestatelessenterpriseJavasessionbean,henceverysimpleandstraightforward.Thisisdemonstratedasfollows:
publicinterfaceHelloWorldBI
{
StringsayHello(intnum,Strings)throws
IOException;
}
2. HelloWorldEJB.class:HelloWorldEJBistheEJBimplementationclass.
WewillagainuseWeblogiclibrariestomakecodingourEJBsimpler;henceweuseWeblogic'sGenericSessionBeanasthebaseclass,whichwillhavedefaultimplementationsfortheEJBinterface.YoumaywanttodeploytheEJBintoadifferentapplicationserverinwhichcasetweakingthecodeandconfigurationfilesshouldbeatrivialexercise.
Thisisshowninthefollowingcode:
publicclassHelloWorldEJBextends
GenericSessionBean
implementsHelloWorldBI
{
publicStringsayHello(intnum,Strings)
{
System.out.println("sayHellointhe
HelloWorldEJBhas"+"beeninvokedwith
arguments"+s+"and"+num);
StringreturnValue="Thismessagebroughtto
youbythe"+"letter"+s+"andthenumber
"+num;
returnreturnValue;
}
}
3. xfire-servlet.xml:ForreaderswhoarefamiliarwithSpring,xfire-servlet.xmlisselfexplanatorybutfortheinterestofothers,wewillexplainthemainaspects,usingthefollowingcode:.
<?xmlversion="1.0"encoding="UTF-8"?>
<beans>
<import
resource="classpath:org/codehaus/xfire/spring/
xfire.xml">
<beanid="jndiTemplate"
class="org.springframework.jndi.JndiTemplate">
<propertyname="environment">
<props>
<propkey="java.naming.factory.initial">
weblogic.jndi.WLInitialContextFactory
<prop>
<propkey="java.naming.provider.url">
t3://localhost:7001
</prop>
</props>
</property>
</bean>
<beanid="sessionEjbProxy"
class="org.springframework.ejb.access.
SimpleRemoteStatelessSessionProxyFactoryBean">
<propertyname="jndiName">
<value>esb-statelessSession-TraderHome</value>
</property>
<propertyname="jndiTemplate">
<refbean="jndiTemplate">
<property>
<propertyname="resourceRef">
<value>false</value>
</property>
<propertyname="lookupHomeOnStartup">
<value>false</value>
</property>
<propertyname="businessInterface">
<value>
examples.webservices.basic.statelessSession.HelloWorldBI
</value>
</property>
</bean>
<beanid="webService"
class="org.codehaus.xfire.spring.remoting.XFireExporter">
<propertyname="style">
<value>rpc</value>
</property>
<propertyname="use">
<value>encoded</value>
</property>
<propertyname="serviceFactory">
<refbean="xfire.serviceFactory">
<property>
<propertyname="xfire">
<refbean="xfire">
<property>
<propertyname="serviceBean">
<refbean="sessionEjbProxy">
<property>
<propertyname="serviceInterface">
<value>
examples.webservices.basic.
statelessSession.HelloWorldBI
</value>
</property>
</bean>
<bean
class="org.springframework.web.servlet.handler.
SimpleUrlHandlerMapping">
EJB-XFiresampleclasses<property
name="urlMap">
<map>
<entrykey="/InvokeService">
<refbean="webService">
<entry>
</map>
</property>
</bean>
</beans>
xfire-servlet.xmldefinestheSpringapplicationContextforXFire.ThefirstpartisdefiningajndiTemplatepointingtheapplicationservercontext.jndiTemplateprovidesmethodstolookupandbindobjects.Weareusingweblogic.jndi.WLInitialContextFactoryhere,butthisneedstobechangedtosuityourapplicationserverenvironment.SinceourEJBisaremotestatelesssessionbean,wecanusetheSpringprovidedSimpleRemoteStatelessSessionProxyFactoryBeanclassforproducingproxiestolookupandaccessservices.
ThejndiTemplatepropertysuppliesdetailstolookupwhereasthebusinessInterfacepropertyspecifiesthebusinessinterface
implementedbytheservice.ThismuchisenoughtogetahandleontheremoteserviceandthenextpartistoexporttheservicefromwithintheXFirecontext,whichwecandousingtheXFireSpringXFireExporter.NexttheSimpleUrlHandlerMappingwillrouteanyrequestsofURLpattern,/InvokeService,totheaboveexportedservice.
4. web.xml:web.xmlisasshowninthefollowingcode,whichisagainsimilartothatinthepreviousexample.
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INFxfire-servlet.xml
classpath:org/codehaus/xfire/spring/xfire.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>xfire</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>xfire</servlet-name>
<url-pattern>services*</url-pattern>
</servlet-mapping>
</web-app>
5. build.xml:Thebuild.xmlrequiresspecialattentioninthiscasebecauseweexplicitlyrefertotheEJBclientjar.WegeneratethisasapartoftheEJBbuildprocessandlater,duringXFireexport,weincludethisclientjartooalongwiththewarfileastheXFireruntimerequiresthebusinessinterface,home,andremotestubsofEJB,andothersimilarhelperclassesduringserviceinvocation.
Thebuild.xmlisshownasfollows:
<targetname="copyjars">
<copytodir="${tomcat.home}/lib">
<fileset
dir="${bea.home}/weblogic812/server/lib">
<includename="weblogic.jar">
<fileset>
</copy>
<copytodir="${build.dir}WEB-INFlib">
<fileset
dir="${bea.home}/weblogic812/samples/server/
examples/build/clientclasses">
<includename="${ejb.client.jar}">
<fileset>
</copy>
</target>
RunningtheSampleRunningthesampleinvolvesmultiplestepsthatarelistedasfollows:
DeployingtheEJB:TodeploytheEJB,wehavetofollowgeneralEJBdeploymentstepsasspecifiedinWeblogicdocumentation.
First,changedirectorytotheEJBsamplesdirectoryasshownhere:
cdch05\04_XFireExportAndBindEjb\ejb
NowsettheenvironmentvariablesforthebuildconsoleaspertheWeblogicdocumentationandthenusetheantscriptprovidedalongwiththeWeblogicserverbundle.Forthat,dothefollowing:
%wl.home%\samples\domains\examples\setExample
sEnv.bat
%wl.home%\server\bin\ant
WecaneventestwhetherourEJBdeploymentwentfinebyexecutingatestclient,asshownhere:
%wl.home%\server\bin\antrun
XFireexportandBindEJB:Inthisstep,wecreatethewebapplicationin.warformatanddeployitinthewebserver.Changedirectorytoch05\04_XFireExportAndBindEjb\XFireBindandexecuteanttobuildthewebapplication,asshownhere:
cdch05\04_XFireExportAndBindEjb\XFireBind
ant
Thiswillgeneratethewarfile,whichinturncontainsallrequiredlibrariesextractedoutfromtheXFireinstallationfolder.FolderdistwillcontainXFireBindEjb.war,whichshouldbedeployedinthewebappsfolderofTomcat(oranyotherrelevantwebserver).Now,restarttheserver.
ThewebservicewouldhavebeenexposedbynowandtheservicedefinitioncanbeaccessedusingthefollowingURL:
http://localhost:8080/XFireBindEjbservices
InvokeService?WSDL
WecannowwriteaClientsimilartowhatwehaveseeninthepreviousfewexamplestotestthewebservice.
Toruntheclient,assumingthatyouhavealreadycompiledtheclient,whilebuildingthesample,executeantasfollows:
antrun
XFireforLightweightIntegrationAlmostallliteraturethatwehavebeenreadingaboutXFire,isfordeployingandaccessingwebserviceinalightweightmanner.SincethistextisspeakingonSOI,weareinterestedintheSOIaspectsofXFire.Wehavedemonstratedthisthroughtheexamplesinthischapter.Later,whenwelookattheServiceMixexamples,wewillseetherealpowerofXFire,especiallytheXFireProxyclasses.
SummaryWebservicesprovideuswithameanstoattainSOA-basedarchitectures.Withthegrowingnumberoftechnologyframeworksavailabletoday,itiseasytodeploywebservices.
XFireisaSOAPstackwithwhichwecanquicklyandeasilyexposewebservices.Asseeninthischapter,acombinationof
technologystackslikeXFireandSpringcanhelptobindexternalservices,includingexternalEJBservices.Oncebound,theseservicescanbere-publishedaswebservicessothattheybecomefirewallfriendly.ThisissimilartoJBIbindingofservicesprovidingamediationlayerforserviceintegration,moreofwhichwewillseeinlaterchapters.
WenowhavehadenoughoftraditionalbindingsandbindingsusingXFire.WiththisbackgrounditistimenowtodelvedeepintoJBIandrelatedservices.WewillcontinuewithmoreJBIdiscussionsinthenextchapterbyunderstandingtheJBIpackaginganddeploymentmodel.
Chapter6.JBIPackagingandDeploymentSmallthingsmatter;whetherpackaginganddeploymentaresmallerconcernscomparedtodesignanddevelopment,isstillunderdispute.However,onethingisclear,thatastandardwayofpackaginganddeploymentpromotescross-platformandcross-vendorportabilityofcomponents,whetheritisourfamiliar.jar,.war,and.rarfilesorthenewJBIarchivedefinedbytheJBIspecification.
ServiceMixisacontainerforJBIcomponents.AtthesametimetheServiceMixJBIcontainerbyitselfisaJBIcomponent.ThischaracteristicenablesServiceMixtobedeployedasastandardJBIcomponentintoanothervendor'sESBcontainer,providedthehostESBcontainersupportsJBIcomponents.Thisissimilartoajava.awt.Framewhichisacomponentthatyoucanincludeinacontainer.Atthesametime,theFramebyitselfisacontainerwhichcancontainothercomponents.ServiceMixisanalogoustoourFrameexample.
WhenwesayaServiceMixcontainerisaJBIcomponent,itmeansthatahostcontainer(likeOpenESBfromSun)canmakeuseofalmosteveryServiceMixcomponent,whetherthecomponentisastandardJBIcomponentoralightweightcomponent(thedifferencebetweenthesetwoisexplained
later).Thepromiseofthismodelisthatthedeveloper-createdServiceMixcomponentscanbereusedinanyotherJBIcontainer.
ThischapterdealswiththedetailsofhowwepackageanddeployJBIcomponentsintoServiceMix.Wewilllookintothefollowing:
Installation,serviceassembly,andserviceunitpackaging
StandardversuslightweightJBIcomponentsinServiceMix
Apackaginganddeploymentsample
PackaginginServiceMixServiceMix,beingJBI-compliant,followstheJBIpackagingschema.JBIspecificationdefinesstandardpackagingforbothinstallationofcomponentsanddeploymentofartifactstothosecomponentsthatfunctionascontainersforothercomponents.
InstallationPackagingJBItalksabouttwotypesofJBIcomponentsforinstallation—aJBIcomponentandashared-libraryforusebysuchcomponents.TheJBIinstallationpackageisaZIParchivefile.ThisZIParchivehascontentsthatareopaquetoJBIexceptforthesocalledinstallationdescriptorthatmustbenamedandlocatedasfollows:
META-INFjbi.xml
Thejbi.xmlmustconformtoeitherthecomponentinstallationdescriptorschemaortheshared-libraryinstallationdescriptorschema.Asampleinstallationdescriptorisshowninthefollowingcode:
<?xmlversion="1.0"encoding="utf-8"?>
<jbiversion="1.0"
xmlns="http://java.sun.com/xml/ns/jbi"
xmlns:sam="http://www.binildas.com/esb/sample">
<componenttype="service-engine">
<identification>
<name>sample-engine-1</name>
<description>Anexampleservice
engine</description>
<sam:TypeInfopart-number="012AB490-578F-114FAA">
BPEL:2.0:XQuery:1.0:XPath:2.0:XPath:1.0
</sam:TypeInfo>
</identification>
<component-class-namedescription="sam">
com.binildas.esb.Sample1
</component-class-name>
<component-classpath>
<path-element>Sample1.jar</path-element>
</component-classpath>
<bootstrap-class-name>
com.binildas.esb.Sample1Bootstrap
</bootstrap-class-name>
<bootstrap-classpath>
<path-element>Sample1.jar</path-element>
</bootstrap-classpath>
<shared-library>slib1</shared-library>
<sam:Configurationversion="1.0">
<sam:ThreadPoolsize="10">
<sam:Queue1size="50">
</sam:Configuration>
</component>
</jbi>
Thejbi.xmlcanincludeextensionelements.IfyouobservethesampledescriptorabovetherearetwoextensionelementsnestedbetweentheConfigurationelements.Theseextensionelementsprovidecomponentspecificinformation,usinganXMLnamespacethatisoutsidethatofdocumentelements(http://www.binildas.com/esb/sampleinourcase).TheyareThreadPoolandQueue1.JBIimplementationsandcomponentimplementationsmayusetheseextensionelementstoprovideextra,componentspecificinformationfortheuseofthecomponent,componenttooling,orboth.Forexample,youcanthinkofanIDEwhichwillhelpinJBIdevelopmentanddeployment,usingwhichyoucanconfigurethecharacteristicsoftheextensionelements(likethenumberofthreadsinthepool,inoursample).
ServiceAssemblyPackagingAServiceAssembly(SA)deploymentpackagecontainsopaque(toJBI)deploymentartifacts,andadeploymentdescriptor.Thisdeploymentdescriptorisnamedjbi.xmlandprovidesinformationfortheJBIdeploymentservicetoprocessthecontentsofthedeploymentpackappropriately.TheSAthencontainsoneormoreServiceUnit(SU)archives,allcontainedwithinaZIParchivefile.AsampledeploymentdescriptorreferringtotwoSUsisshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<jbixmlns="http://java.sun.com/xml/ns/jbi"
version="1.0">
<service-assembly>
<service-assembly>
<identification>
<name>soap-demo</name>
<description>Soapdemo</description>
</identification>
<service-unit>
<identification>
<name>engine-su</name>
<description>Containstheservice</description>
</identification>
<target>
<artifacts-zip>engine-su.zip</artifacts-zip>
<component-name>servicemix-jsr181</component-
name>
</target>
</service-unit>
<service-unit>
<identification>
<name>binding-su</name>
<description>Containsthebinding</description>
</identification>
<target>
<artifacts-zip>binding-su.zip</artifacts-zip>
<component-name>servicemix-http</component-name>
</target>
</service-unit>
</service-assembly>
</jbi>
ThisdeploymentdescriptorreferstotwodifferentSUsnamelyengine-suandbinding-su.ThesetwoSUarchives,plusthedescriptoritself,arecombinedintoasingleZIParchivetoformtheSA.ThedeploymentdescriptorisplacedinsidetheZIParchiveinadirectorystructureasgiveninthefollowing,whichwillbeexplainedwithfigureslaterinthischapter:
META-INFjbi.xml
ServiceUnitPackagingTheSAcontainsopaque(toJBI)deploymentartifactscalledSUs,whichareagainZIParchivefiles.ThesearchivescontainasingleJBI-defineddescriptorfile:
META-INFjbi.xml
Thejbi.xmldescriptorprovidesinformationabouttheservices,whicharestaticallyprovidedandconsumedasaresultofdeployingtheSUtoitstargetcomponent.
TheServiceMixJBIcontaineralsosupportsXBean-baseddeployment—wecandeploySUscontainingafilenamedxbean.xml.Since,atSA-level,theSUsareopaquetoJBIdeployment,eventheSAcontainingXBean-basedSUscanbeportedacrossJBIcontainers.
DeploymentinServiceMixJBIcomponents,bythemselves,canactasJBIcontainers.Addingmoreartifactstoinstalledcomponentsiscalleddeployment.ServiceMixsupportstwomodesofdeployment—standardandJBIcomplaint,andlightweight.
StandardandJBIcompliantUsingthismode,wecaninstallcomponentsatruntimeanddeploySAsontothem.ThesecomponentsareJBI
specificationcompliantandhencetheyareJBIcontainersforothercomponentstoo.TheycanacceptSAdeploymentsandareimplementedusingtheservicemix-commonmodule.SincetheyareJBIcompliant,theyarepackagedasZIParchivefileswithajbi.xmldescriptor.
ExamplesofafewServiceMixstandardJBIcomponentsareshowninthefollowinglist:
servicemix-jsr181
servicemix-drools
servicemix-http
servicemix-jms
Wecanalsoconfiguretheabovementionedstandardcomponents,tobeusedinastaticdeploymentmodeusingtheservicemix.xmlconfigurationfile.
Wecandeploylightweightcomponentsinthismode.Todothat,lightweightcomponentsmustbedeployedtotheservicemix-lwcontainer.
LightweightLightweightcomponentsarePOJOcomponentsimplementingtherequiredJBIinterfaces.Theydon'tfollowstandardJBIpackaging;hence,donotsupportSUdeployments.Duetothisreason,theycannotnormallybedeployedatruntime.Incaseweneedtodeploythematruntime,wecandeploythemontheservicemix-lwcontainer(lightweightcontainer).
LightweightcomponentsnormallyinherittheComponentSupportclassdirectlyorindirectly,andaremainlyintheservicemix-componentsmodule.Wenormallyusetheservicemix.xmlstaticconfigurationfilewhenwewanttorunasingleapplicationfortestingpurposes,orwhenweembedServiceMixinawebapplication,forexample.
AFewexamplesareshowninthefollowinglist:
JDBCcomponent
Quartzcomponent
XSLTcomponent
PackagingandDeploymentSampleWewillnowcreateSUsandSAs,anddeploythemintotheServiceMixJBIcontainer.Thewholeprocesscanbedividedintotwophases,withmultiplestepsineachphase.
Thetwophasesintheprocessarethefollowing:
Componentdevelopment
Componentpackaging
PhaseOne—ComponentDevelopment
Thisphaseincludescodingandbuildingthecodebase.Wehavethecodebasesplitupintomultiplefolderseachrepresentingseparateartifacts,whichgointothefinalSAsasshowninthefollowingfigure.
Thecomponentsfolderissupposedtocontainlightweight(orPOJO)components,butinourcase,wehaveasimpleserviceclass(HelloServicePojo)implementingaBI(HelloServiceBI),thisisshowninthefollowingcode:
publicinterfaceHelloServiceBI
{
Stringhello(Stringphrase);
Stringhello(Stringphrase);
}
publicclassHelloServicePojoimplements
HelloServiceBI
{
privatestaticlongtimes=0;
publicStringhello(Stringphrase)
{
System.out.println("HelloServiceBean.hello{"+
(++times)+"}...");
return"FromHelloServiceBean:HELLO!!Youjust
said:"+phrase;
}
}
PhaseTwo—ComponentPackagingWewillnowhavetwoServiceUnits—oneaSEandtheotheraBC.BoththeseServiceUnitswillbepackagedintoasingleServiceAssemblysothatwecandeploythemintotheESB.Theservicemix-sharedServiceAssemblyprovidescommonservicesandhencewewillalsodeploythattoointotheESB.Thefullsetupisasshowninthefollowingfigure:
WewillnowlookintothepackagingofindividualSUsandSAs.
Theengine-su(ServiceEngineServiceUnit)isbasedonxbean.xml,whichleveragesjsr181:endpointtoexposeourserviceclassasawebservice.Thisisshowninthefollowingcode:
<?xmlversion="1.0"?>
<beans
xmlns:jsr181="http://servicemix.apache.org/jsr181/1.0"
xmlns:demo="http://binildas.com/esb/sample">
<classpath>
<location>.</location>
</classpath>
<jsr181:endpoint
pojoClass="samples.HelloServicePojo"
annotations="none"service="demo:hello-service"
endpoint="hello-service"
serviceInterface="samples.HelloServiceBI">
<beans>
Thebinding-su(BindingComponentServiceUnit)isalsobasedonxbean.xml,whichleverageshttp:endpointintheconsumer(consumertoNMR)role.Thisisshowninthefollowingcode:
<?xmlversion="1.0"?>
<beans
xmlns:http="http://servicemix.apache.org/http/1.0"
xmlns:demo="http://binildas.com/esb/sample">
<http:endpointservice="demo:hello-service"
endpoint="hello-service"role="consumer"
locationURI="http://localhost:8192/Service/"
defaultMep="http://www.w3.org/2004/08/wsdl/in-out"
soap="true">
<beans>
ThetwoServiceUnitscanbenowpackagedintoasingleServiceAssembly.So,thesetwoSUsareconfiguredinthe.xmlfileshownasfollows:
META-INFjbi.xml
Thecontentsofjbi.xmlfileareasfollows:
<?xmlversion="1.0"encoding="UTF-8"?>
<jbixmlns="http://java.sun.com/xml/ns/jbi"
version="1.0">
<service-assembly>
<identification>
<name>soap-demo</name>
<description>Soapdemo</description>
</identification>
<service-unit>
<identification>
<name>engine-su</name>
<description>Containstheservice</description>
<description>Containstheservice</description>
</identification>
<target>
<artifacts-zip>engine-su.zip</artifacts-zip>
<component-name>servicemix-jsr181</component-
name>
</target>
</service-unit>
<service-unit>
<identification>
<name>binding-su</name>
<description>Containsthebinding</description>
</identification>
<target>
<artifacts-zip>binding-su.zip</artifacts-zip>
<component-name>servicemix-http</component-name>
</target>
</service-unit>
</service-assembly>
</jbi>
Asisevident,theServiceAssemblyencapsulatestwoServiceUnits—engine-suandbinding-su.
Thus,theServiceUnitisaZIParchivethatwillcontainyourapplication'sJavaclassfilesandtheservicemix.xmlconfigurationfile.TheServiceUnitcanalsocontainajbi.xmlfilewhichprovidesinformationaboutservicesstaticallyprovidedandconsumed.ThenameoftheZIParchivethatwecreatehereislaterreferredtofromthejbi.xmlfileoftheenclosingServiceAssembly.
Buildingandpackagingcanbeautomatedusingtheantbuildtoolwiththehelpofbuild.xml,showninthefollowingcode:
<projectname="jms-binding"default="setup"
basedir=".">
<targetname="build-components"depends="init">
<javacsrcdir="${comp.src.dir}"
destdir="${comp.build.dir}">
<classpathrefid="javac.classpath">
<javac>
</target>
<targetname="build-engine-su"
depends="build-components">
<zipdestfile="${build.dir}/engine-su.zip">
<filesetdir="${comp.build.dir}"/>
<filesetdir="${su.engine.src.dir}">
<zip>
</target>
<targetname="build-binding-su">
<zipdestfile="${build.dir}/binding-su.zip">
<filesetdir="${su.binding.src.dir}">
<zip>
</target>
<targetname="build-sa"
depends="build-engine-su,build-binding-su">
<zipdestfile="${build.dir}/soap-demo-sa.zip">
<filesetdir="${build.dir}"
includes="engine-su.zip">
<filesetdir="${build.dir}"
includes="binding-su.zip">
<filesetdir="${sa.src.dir}">
<zip>
</target>
<targetname="setup"depends="build-sa">
<mkdirdir="${install.dir}">
<mkdirdir="${deploy.dir}">
<copytodir="${install.dir}">
<filesetdir="${servicemix.home}/components"
includes="jsr181">
<filesetdir="${servicemix.home}components"
includes="http">
<filesetdir="${servicemix.home}components"
includes="servicemix-shared">
<copy>
<copyfile="${build.dir}/soap-demo-sa.zip"
todir="${deploy.dir}">
<target>
</project>
Inthesetuptargetwecanseethatwecopythejsr181component,httpcomponent,andservicemix-sharedfromtheServiceMixinstallationpathtoourtargetinstalldirectory.ThesearestandardJBIcomponentsontowhichwearedeployingtheSUartifacts.Whenwedothat,ifServiceMixisalreadyrunning,itwilldetectthefilepresentthereandstartit.
RunningthePackagingandDeploymentSampleAsafirststepandifyouhaven'tdoneitbefore,editexamples.PROPERTIESprovidedalongwiththecodedownloadforthischapterandchangethepathstheretomatchyourdevelopmentenvironment.ThecodedownloadforthischapteralsoincludesaREADME.txtfile,whichgivesdetailedstepstobuildandrunthesamples.
Nowweneedtobuildthesamples.Forthis,changedirectorytoch06\SoapBindingandthenexecuteant,asshownhere:
cdch06\SoapBinding
ant
Thiswillbuildtheentiresample.
Nowwearegoingtorunthisexampleasstandalone.Thatis,ServiceMixwillbestartedandthentheSOAPdemoisdeployedandrun.Thisisdonebyexecutingtheservicemix.xmlfilefoundinthetopmostfolder(ch06\SoapBinding).
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0">
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.
config.PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<sm:containerid="jbi"rootDir="./wdir"
installationDirPath="./install"
deploymentDirPath="./deploy"flowName="seda">
<sm:activationSpecs>
</sm:activationSpecs>
</sm:container>
</beans>
WecanbringupServiceMixbyrunningthefollowingcommands:
cdch06\SoapBinding
%SERVICEMIX_HOME%/bin/servicemixservicemix.xml
WhenwestartServiceMix,theJBIcontainerisconfiguredusingtheaboveservicemix.xmlfile.
Torunthedemo,thereisaClient.htmlfileprovidedagaininthetopfolder.TheClientwillsendthefollowingrequest:
<SOAP-ENV:Envelopexmlns:SOAP-ENV=
"http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<ns1:hello
xmlns:ns1="http://binildas.com/esb/sample"SOAP-
ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<phrasexsi:type="xsd:string">what'syour
name?
</phrase>
</ns1:hello>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
TheclientsendstheaboveSOAPrequesttohttp://localhost:8192/Service/.As,wealreadyconfiguredServiceMixhttp:endpointlisteninginport8192,theSOAPrequestwillbeinterceptedandsenttotheJBINMR.http:endpointhastheconsumerrolewhenitsendsaSOAPrequesttotheNMRanditwillberoutedto
http:endpointlisteninginport8192.ThisserviceistheJSR181bindingcomponentforourserviceimplementationclass,whichwheninvokedwillcarryoutthebusinessfunctionalityandanyresponseisreturnedthroughasimilarchannelbacktotheclient.
SummaryWeusemultiplearchiveformatsforvariousJ2EEcomponents—.jar,.war,.ear,and.rararefewamongstthem.Now,JBIspecificationrecognizes.zipasavalidarchiveformatforJBIcomponents.SUsandSAsarepackagedasvalid.zipfilesandaredeployedintoJBIcompliantcontainers.Inthischapter,wehaveseenhowtowritecodefromscratch,packageitintostandardJBIformats,anddeployittotheESBruntime.Wewillfollowsimilarpackagingformostofoursamplesinthesubsequentchapters.
ThenextchapterwillteachhowtocustomcodeJBIcomponentsonourown,sothattheycantakepartinthemessageexchangeshappeningthroughtheJBIbus.
Chapter7.DevelopingJBIComponentsUntillnow,youhavebeenassemblingJBIcomponentswhicharepre-builtandavailablealongwiththeServiceMixinstallationinyourownway.TheaimofthischapteristogetstartedindevelopingyourowncomponentsanddeployingthemintotheServiceMixJBIcontainer.Inthischapter,wewillvisitthecoreAPIfromServiceMixaswellasfromtheJBIspecification,whichwillfunctionasusefulhelperclassesusinglightweightcomponents.WewillalsocreateourownJBIcomponentanddeployitintotheJBIbus.
DevelopingJBIcomponentsinServiceMixrequiresthedevelopertowriteabitofplumbingcode,whichmayormaynotbesoappealing.Tomakethedeveloper'slifeeasy,ServiceMixsupportsSpring-basedPOJOclassesandtheirconfiguration.ServiceMixalsoprovidesmanycomponenthelperclasses.Itisuptothedeveloperwhethertomakeuseofthesehelperclasses,ordeveloptheirowncomponentsorcodeagainstthecoreAPIsofServiceMixandJBI,thoughthereisnoreasonwhyanyoneshouldn'tbeusingthehelperclasses.
So,wewillcoverthefollowinginthischapter:
NeedforcustomJBIcomponents
ServiceMixcomponenthelperclasses
Create,deploy,andrunJBIcomponents
Buildandrunasample
NeedforCustomJBIComponentsWehavealreadyseenmanyServiceMixcomponents,bothJBIcompliantandlightweight.ManyofthemareavailableinsidethecomponentsfolderintheServiceMixinstallation.Anaturalqueryinthiscontextis"WhydoesoneneedtodevelopcustomcomponentsinServiceMix?".OftenIseemyselfasalazyprogrammer,tryingtoreusecodes,components,orservicesratherthanhandcodethemeverytime.
Goingbythattrend,IamalsocompelledtolookatServiceMixwithanaimtoreuseanythingandeverything,andnottohandcodeanything.Thepropositionlooksfine,butthetruthisthattheworldisnotidealallthetime.Inanidealworld,wewillhavealltheServiceMixcomponents,tools,andhooksavailable,sothatwecanassembleorreconfigurethecomponentstosuitourneeds.Thismakessenseinapureintegrationinitiativewhereweonlyintegrate,anddonotdevelopanything—afterall,JBIandServiceMixisallaboutintegration.However,sincetheworldisfarfromidealandallofuswillhaveourownintegrationproblemsandscenarios.Often,wewillhavetocustomcodeintegrationwrappers,messageorchestrationlogic,orerrorhandlinglogic.ThislogiccanbecodedintocomponentscreatedoutofServiceMixhelperclassesandeasilydeployedintoaServiceMix
container.
ServiceMixComponentHelperClassesServiceMixprovidesalotofplumbingcodeintheformofreusablecomponenthelperclasses.Mostoftheseclassesareabstractbaseclassesfromwhichthedevelopercanderivetheirownclassestoputcustomlogic.Themainclassesofinterestandtheirrelationshipareshowninthefollowingfigure:
MessageExchangeListenerMessageExchangeListenerisaServiceMixpackageinterface,verysimilartotheJMSMessageListener.Thisinterfaceisshowninthefollowingcode:
packageorg.apache.servicemix;
importjavax.jbi.messaging.MessageExchange;
importjavax.jbi.messaging.MessagingException;
publicinterfaceMessageExchangeListener
{
/**
MessageExchangepasseddirectlytothelistener
insteadofbeingqueued
@paramexchange@throwsMessagingException
/
publicvoidonMessageExchange(MessageExchange
exchange)throwsMessagingException;
}
Whenourcustomcomponentsimplementthisinterface,wewillbeabletoreceivenewmessageexchangeseasily,ratherthanwritinganewthread.ThedefaultJBIasynchronousdispatchmodeliswhereathreadisusedperJBIcomponentbythecontainer.However,whenthecomponentimplementtheMessageExchangeListenerinterface,theServiceMixcontainerwilldetecttheuseofthisinterfaceandbeabletoperformimmediatedispatch.
TransformComponentSupportTransformComponentSupportcontainsadefault
implementationfortheonMessageExchangemethod.Thecodeismoreexplanatorythanatextualdescriptionofthesequences.Hence,let'sreproducethatinthefollowingcode:
publicvoidonMessageExchange(MessageExchange
exchange)
{
if(exchange.getStatus()==ExchangeStatus.DONE)
{
return;
}
elseif(exchange.getStatus()==
ExchangeStatus.ERROR)
{
return;
}
try
{
InOnlyoutExchange=null;
NormalizedMessagein=getInMessage(exchange);
NormalizedMessageout;
if(isInAndOut(exchange))
{
out=exchange.createMessage();
}
else
{
outExchange=
getExchangeFactory().createInOnlyExchange();
out=outExchange.createMessage();
}
booleantxSync=exchange.isTransacted()&&
Boolean.TRUE.
equals(exchange.getProperty(JbiConstants.SEND_SYNC));
copyPropertiesAndAttachments(exchange,in,out);
if(transform(exchange,in,out))
{
if(isInAndOut(exchange))
{
exchange.setMessage(out,"out");
if(txSync)
{
getDeliveryChannel().sendSync(exchange);
}
else
{
getDeliveryChannel().send(exchange);
}
}
else
{
outExchange.setMessage(out,"in");
if(txSync)
{
getDeliveryChannel().sendSync(outExchange);
}
else
{
getDeliveryChannel().send(outExchange);
}
exchange.setStatus(ExchangeStatus.DONE);
getDeliveryChannel().send(exchange);
}
}
else
{
exchange.setStatus(ExchangeStatus.DONE);
getDeliveryChannel().send(exchange);
}
}
catch(Exceptione)
{
try
{
fail(exchange,e);
}
catch(Exceptione2)
{
logger.warn("Unabletohandleerror:"+e2,e2);
if(logger.isDebugEnabled())
{
logger.debug("Originalerror:"+e,e);
}
}
}
}
Theabovecodecallstransform(exchange,in,out).Bydoingso,itisinvokingtheabstractmethodinTransformComponentSupport.Theabstractmethodisreproducedasfollows:
protectedabstractboolean
transform(MessageExchangeexchange,
NormalizedMessagein,NormalizedMessageout)
throwsException;
Hence,itiseasytojustimplementthetransformmethodinthecustomcodeandletthehelperclassworksbehindthescenesforallmessageexchanges.
ComponentSupportandPojoSupportaretheothertwohelperclassesinthehierarchy.
Create,Deploy,andRunJBIComponentThissectioncoversfromendtoend,thecreation,deployment,andrunningofasampleJBIcomponentinServiceMix.
Followingthebasicsdemonstratedinthischapter,readerscancodeJBIcomponentstosuittheirownrequirements.Wewillalsoseemanysuchcomponentsintheexamplesincomingchapters.Thecodeforthissampleiskeptinch07\CustomComponentfolder.
CodeHttpInterceptorComponentHttpInterceptor,asthenameimplies,willinterceptmessagescomingintheHTTPchannel.Itthenprintsoutthemessagetotheconsole,andsendssomemessagebackthroughtheresponsechannel.Toquicklycodeourcomponent,wewillextendtheServiceMixcomponenthelperclassnamelyTransformComponentSupport.
Thisisdemonstratedinthefollowingcode:
publicclassHttpInterceptorextends
TransformComponentSupport
{
publicHttpInterceptor(){}
protectedbooleantransform(MessageExchange
exchange,NormalizedMessagein,NormalizedMessage
out)throwsMessagingException
{
NormalizedMessagecopyMessage=
exchange.createMessage();
getMessageTransformer().transform(exchange,in,
copyMessage);
Sourcecontent=copyMessage.getContent();
System.out.println("HttpInterceptor.transform02.
content="+content);
StringcontentString=null;
if(contentinstanceofDOMSource)
{
contentString=XMLUtil.node2XML(((DOMSource)
content).getNode());
System.out.println("HttpInterceptor.transform03.
contentString="+contentString);
}
out.setContent(newStringSource("<?xml
version=\"1.0\"encoding=\"UTF-8\"?>
<Response>ResponseFromServer</Response>"));
returntrue;
}
}
Aswedescribedearlier,wewillimplementtheabstracttransformmethodinTransformComponentSupport.TheTransformmethodwillhaveareferencetotheMessageExchangeandalsototheinandoutNormalizedMessages.Wefirstcopythecontentsfrom
theinmessageandprintthatouttotheconsole.Then,wecreateanewStringSourcewithsomemessagefromtheserver,sendingthattotheoutNormalizedMessages.Thecodeisassimpleasthat,sincemostoftheplumbinghasalreadybeendoneforyoubythebaseclassmethods.
ConfigureHttpInterceptorComponentAs,wecanconfiguretheHttpInterceptorcomponentasSU,wewilldotheconfigurationofthiscomponentasaSUintheservicemix.xmlfilekeptatch07\CustomComponent\su\servicemix.xml.
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:demo="http://www.binildas.com/esb/customcomponent">
<classpath>
<location>.</location>
</classpath>
<sm:serviceunitid="jbi">
<sm:activationSpecs>
<sm:activationSpeccomponentName="interceptor"
endpoint="interceptor"
service="demo:interceptor">
<sm:component>
<beanclass=
"com.binildas.esb.customcomponent.HttpInterceptor">
<sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:serviceunit>
</beans>
ThisisdifferentfromtheXBean-basedpackagingexample,thatwesawinthepreviousexample.As,weareusingservicemix.xmltospecifytheSU.Thus,wecanseethattherearemultiplewaysbywhichwecanconfigureandpackageourSUs.
PackageHttpInterceptorComponentInChapter6,wesawhowtopackageanddeploycomponentsinServiceMix.Wewillfollowthesamepackagingmethodologyhere.WewillcreateanSUandthenpackageitintoanSA.
WehavealreadyseentheSUconfiguration,letusnowlookintotheSAconfigurationasfollows:
\sa\META-INF\jbi.xml
ThecontentoftheJbi.xmlfileisshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<jbixmlns="http://java.sun.com/xml/ns/jbi"
version="1.0">
<service-assembly>
<identification>
<name>InterceptorAssembly</name>
<name>InterceptorAssembly</name>
<description>InterceptorService
Assembly</description>
</identification>
<serviceunit>
<identification>
<name>Interceptor</name>
<description>InterceptorService
Unit</description>
</identification>
<target>
<artifacts-zip>Interceptor-su.zip</artifacts-zip>
<component-name>servicemix-
lwcontainer</component-name>
</target>
</serviceunit>
</service-assembly>
</jbi>
Here,wepackagetheInterceptorServiceUnitintotheSA.ThemainpointtobenotedintheSAjbi.xmlisthetargetelementoftheserviceunit.Here,wespecifythattheSUartifact(thatis,Interceptor-su.zip)istobedeployedintotheservicemix-lwcontainertargetcontainer.
DeployHttpInterceptorComponentTodeploytheHttpInterceptorcomponent,wehaveaservicemix.xmlfileinthetopmostfoldertostarttheServiceMixcontainer.
Thecontentoftheservicemix.xmlfileisshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:demo="http://www.binildas.com/esb/customcomponent">
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<sm:containerid="jbi"rootDir="./wdir"
installationDirPath="./install"
deploymentDirPath="./deploy"flowName="seda"
monitorInstallationDirectory="true"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpeccomponentName="httpReceiver"
service="bt:httpBinding"endpoint="httpReceiver"
destinationService="demo:interceptor">
<sm:component>
<beanclass="org.apache.servicemix.components.
http.HttpConnector">
<propertyname="host"value="127.0.0.1"/>
<propertyname="port"value="8912">
<bean>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
</beans>
Thefirstthingtonotehereisthatwehave
installationDirPath="./install"fortheJBIcontainer.ThisiswhereweplaceourJBIcomponents,whicharetobeinstalledbyServiceMix.Hence,theycanactascontainersforcomponentslikeourHttpInterceptor.
ItisalsoworthnotingthatwehaveanHttpConnectorconfiguredwithoursample,andHttpInterceptor,asthedestinationServicesothatwehaveawaytotestoursampletoo.
BuildandRuntheSampleAsafirststepandifyouhaven'tdoneitbefore,editexamples.PROPERTIESprovidedalongwiththecodedownloadforthischapterandchangethepathstheretomatchyourdevelopmentenvironment.ThecodedownloadforthischapteralsoincludesaREADME.txtfile,whichgivesdetailedstepstobuildandrunthesamples.
Thebuild.xmlisasusualbutwewilllistthemajordifferenceshere.
As,wewantHttpInterceptorSUtobedeployedintoservicemix-lwcontainerwhilebuildingthecodebase,wewillalsocopytheservicemix-lwcontainerfromServiceMixinstallationtoinstallationDirPath.
<copytodir="${install.dir}"overwrite="true">
<filesetdir="${servicemix.home}/components"
includes="lwcontainer">
<filesetdir="${servicemix.home}components"
includes="shared">
<copy>
Executeanttobuildthesampleasshownasfollows:
cdch07\CustomComponent
ant
WecanbringupServiceMixbyrunningthefollowingcommands:
cdch07\CustomComponent
%SERVICEMIX_HOME%/bin/servicemixservicemix.xml
WhenwestartServiceMix,theJBIcontainerisconfiguredusingtheaboveservicemix.xmlfile.Torunthedemo,thereisaClient.htmlfileprovidedagaininthetopfolder.
SummaryInthischapter,welookedatthecoreAPIfromServiceMixaswellasfromtheJBIspecification,whichwillfunctionasusefulhelperclassesusingwhichwecandeveloplightweightcomponentsquickly.
WehavealsocustomcodedaJBIcomponentanddeployeditintotheJBIbus.Youmaynotwanttoalwayscustomcodecomponents.Manytimes,JBIcomponentswillbeavailableasoff-the-shelf-libraries.Suchcomponentscantakepartinthe
messageexchangesthroughtheESBandcanprovideintegrationwithexternalserviceslikeCICSandCORBA,forexample.IfbyanychanceyouwanttocreateyourownJBIcomponents,thenyoucanfollowtheguidelinespresentedinthischapterasastartingpoint.
AswehavecoveredthestandardJBIpackaginganddeploymentmodelinChapter6,wenowhaveenoughtoolsetstodelvedeepintoJBIandESB.WewillcontinueourjourneybylookingatusingSpringbeanstoSpring-wrapanEJBserviceontotheJBIbusinthenextchapter.Bydoingso,wewillexposeEJBasaWSDLcompliantserviceacrossfirewalls—yesreally,wearegoingtodothat!Hence,don'tscrapyourexistinginvestmentsinEJBtillyoucoverthenextchapter.
Chapter8.BindingEJBinaJBIContainerEJBisthedistributedcomponentparadigmintheJava-J2EEworld.EJBprovednottobeapushbuttonsolutionforprogrammingproblems.Still,afewofthepromises(ofcourse,realitytoo)—distributedtransactionpropagation,component-baseddeploymentmodel,andinterface-baseddesign,provedtobereallyuseful.Today,wehavebeentalkingaboutlightweightcontainersandaspect-basedprogramming,andwhetherEJBstillholdsthecrownissomethingwhichhastobeansweredonacasebycasebasis.BeingneitheraproponentnoranopponentofEJB,onethingIhavetoadmitisthattheindustryhasalotinvestedinthistechnology.Scrapingalltheseinvestmentsandimplementingalternatesolutionsissurelynotatopicforourdiscussion,atleastinthistextbook.ForourSOI-baseddiscussion,perhaps,itismoreinterestingtolookathowtoreusethoseexistinginvestments.Hence,wecancontinuebuildingnewersystembasedonhigherlevelsofSOA,maturitycoexistingwitholdfunctionality.Inclearerterms,coexistingservicesandcomponents.
Wewillcoverthefollowinginthischapter:
Componentversusservices.
Indiscriminationatconsumerperspective.
StepwisebindingEJBsample.
ReconcilingEJBresources.
ComponentversusServicesInachapterlikethis,itmakessensetodiscussthedifferencebetweencomponentsandservices.
Componentsarefirst-classdeployableunitspackagedintostandardartifacts.Componentsliveinsomecontainer;thereiscomponent-containerinteractionforcomponentlifecyclemanagementandeventnotification.Thus,componentsarephysicalunits.Componentswillalsoassumeexplicitlyabouttheprotocolandformatofdatasentoverthewire,sincemostofthetimetheyaretechnology-dependent.
ServicesontheotherhandhaveURLaddressablefunctionality,accessibleoverthenetwork.Atleastfromtheconsumerperspective,therearenolifecycleactivitiesassociatedwiththeservice,sinceservicesarestatelessandidempotent.Betweenanytwoserviceinvocations,thereisnostatemaintainedattheprovider-level(ofcourse,therearestatefulservicestoo).Thusservicesarevirtualdistributedcomponents,whichareneutralabouttheprotocolandformatofsendingmessages.Byneutral,wemeanitdoesn'tmatterwhattheunderlyingtechnologyorplatformisaslongastheproviderandconsumeragreestoacommonprotocolandformat.
CoexistingEJBComponentswith
ServicesWeneedtodeviseamechanismbywhichwecanallowcoexistenceofcomponentsandservices.Bycoexistence,wemeanaconsumershouldbeabletoconsumeawebserviceandanEJBservicewithoutanydifference.Traditionalcomponentdevelopers,whoalsoknowhowtodevelopawebservice,willfirstwonderhowthiscanbepossible.Bothhavecompletelydifferentconsumptionmechanisms—awebserviceischaracter-orientedwhereasanEJBserviceisbinary-oriented,justoneofthemanymismatches.
ESBBindingComponents(BC)comestotherescue.ByjudiciouscombinationofBCs,evenanEJBcomponentcanbehookedtotheNMRsothatanyconsumer,whethertheyareinadifferenttechnologylike.NETorMainframe,caninteroperate.Ofcourse,thisisnotsomethingnew,sincewehavebeendoingthisforyearsusingCORBAorCOBOLCopyBooks,butneverinastandardway.NowJBIpromisesthesamesothatinteroperabilityofourcomponentsacrossmultipleJBIcontainersisnolongeradream.
Theadvantageofthiskindofinteroperabilityismultifold.First,evenanorganizationwithlessSOAmaturityimplementationscanquickstarttheirenterpriseefforts,andwhentheydosotheycanreuseexistingITassets.ThisisdifferentfromtheBing-Bangapproach,whichwillreducetheoverallriskconsiderably.Secondly,developerswillbereadytoacceptthechangesincechangeisnotabrupt—changewillstillharmonizetheirpastintellectualspendingintermsoftimeandeffortfordevelopingallthosepast(EJB)components.
IndiscriminationatConsumerPerspectiveWhenwewanttocoexistcomponentsandservicestogether,technicalindiscriminationisveryimportant.Asaconsumercannowusethesamesetoftoolsandmethodologiestoaccessfunctionality,whetheritisa(web)serviceoranEJBcomponent.IfyouhaveprogrammedanEJBorwebservicebefore,youwillagreethatthecontractmodelsaredifferent.InthecaseofanEJB,theconsumer-providercontractistheEJBhomeandEJBremoteinterface(betteristhecasewiththeCORBAworld,wheretheinterfaceistheIDL).Moreover,theseinterfacesdon'tmakeanysensetoanyconsumerwhodoesn'tspeakJava.However,inawebservicethecontractistheWSDL,whichissupposedtobeinterpretedbyanyconsumer.Toindiscriminate,wewillneedtoprovidethesameinterfaceasthewebserviceandseehoweasyitistodowiththehelpofanESB.
BindingEJBSampleWewillnotspendtoomuchtimedescribinghowtowriteanddeployanEJBcomponent,sincetherearealotofbooksandresourcesavailablewhichwilldojustthat.However,wewillspendsometimelookingathowwecanuseSpringbeanstoSpring-wrapanEJBservice.MoretimewillbespentonactualbindingofEJBandrelateddiscussion.Asusual,wewilldothissampleinastepbystepmanner.
StepOne—DefineandDeploytheEJBServiceTheEJBserviceweimplementisverysimple;theclassesandinterfacesinvolvedareshowninthefollowingfigure:
WeneedtoabstractouttheinterfacefromallEJBspecificdetails;hence,wehavefollowedtheBIpatterntodefinetheinterface.HelloServiceBIistheBI,whichisvoidofanyEJBspecificAPI.
packagesamples;
publicinterfaceHelloServiceBI
{
Stringhello(Stringphrase)throws
java.io.IOException;
}
Asafirststepandifyouhaven'tdoneitbefore,edit
examples.PROPERTIESprovidedalongwiththecodedownloadforthischapterandchangethepathstheretomatchyourdevelopmentenvironment.ThecodedownloadforthischapteralsoincludesaREADME.txtfile,whichgivesdetailedstepstobuildandrunthesamples.
Forthesampledeployment,wewilluseBEAWeblogicserver'sexampledomain.Hence,allnecessarydeploymentdescriptorsfortheWeblogicEJBcontainerareprovidedintherespectivefolders.IncaseyouneedtodeploytheEJBintoadifferentvendor'sEJBcontainer,changethedeploymentdescriptorsaccordingly.
Executethefollowingscriptsinthecommandprompttobringuptheserverfirst:
cd
%BEA_HOME%/weblogic812/samples/domains/examples
%BEA_HOME%/weblogic812/samples/domains/examples/s
tartExamplesServer
TobuildanddeploytheEJB,inadifferentcommandpromptchangedirectoryto:
ch08\BindEjb\01_Ejb
%BEA_HOME%/weblogic812/samples/domains/examples/s
etExamplesEnv
%BEA_HOME%/weblogic812/server/bin/ant
Thiswillbuild,package,anddeploytheEJBmoduleintotheWeblogicserver.Itwillalsocreateaclientjarcontainingall
theclient-sidestubs,whichisrequiredlaterforaccessingtheservice.Incaseyouneedtotestwhetheryourdeploymentwentfine,thereisaclientprovidedwhichyoucanexecutebytypingthefollowingcode:
ch08\BindEjb\01_Ejb
antrun
StepTwo—BindEJBtoServiceMixOncetheEJBserviceisupandrunning,wenowwanttoexposetheserviceacrossfirewallsinatechnologyneutralformatandprotocol.Bydoingso,wecanmaketheEJBserviceconsumablebyotherB2Bpartners.ThedeploymentdiagramforanESB-basedsolutionforthesamplescenarioisshowninthefollowingfigure:
Here,theApplicationServerwillhostourEJBcomponentservices.TheESBserver(cluster)infrontoftheApplicationServerwillhosttherequiredBCstoproxytheEJBservicebehindthescenesasfirewall-friendlyservices,consumablebyotherB2Bclients.
InChapter6,youhavealreadyseenhowwecanleveragethe
servicemix-jsr181standardJBIcomponentasacontainerforcustomPOJOclasses,sothatthemethodsdefinedinaPOJOareexposedasservices.WeneedtofollowasimilarapproachtobindanEJBservicetoototheJBIbus,buttheconfigurationisslightlydifferent.Thesamplebindingscenarioinsidethebusisrepresentedinthefollowingfigure:
LetusnowbindtheEJBservicetotheJBIbususingtheservicemix-jsr181component.servicemix-jsr181canbeconfiguredinthelightweightmodetoo.Letuslookintotheservicemix.xmlfileforthat,asshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:http="http://servicemix.apache.org/http/1.0"
xmlns:jsr181="http://servicemix.apache.org/jsr181/1.0"
xmlns:my="http://binildas.com/esb/bindejb">
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<sm:containerid="jbi"useMBeanServer="true"
createMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpec>
<sm:component>
<http:component>
<http:endpoints>
<http:endpointservice="my:HelloServiceBIService"
endpoint="HelloServiceBI"role="consumer"
defaultOperation="hello"
targetService="my:jsrEjbEP"
targetEndpoint="jsrEjbEP"
locationURI="http://localhost:8192/Services/
HelloWebService"soap="true"
defaultMep="http://www.w3.org/2004/08/wsdl/
in-out">
<http:endpoints>
</http:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="jsrEjbBC"
service="my:jsrEjbBC"endpoint="jsrEjbBC">
<sm:component>
<jsr181:component>
<jsr181:endpoints>
<jsr181:endpointannotations="none"
service="my:jsrEjbEP"endpoint="jsrEjbEP"
serviceInterface="samples.HelloServiceBI">
<jsr181:pojo>
<beanclass="org.springframework.ejb.
access.SimpleRemoteStatelessSession
ProxyFactoryBean">
<propertyname="jndiName"value=
"sample-statelessSession-TraderHome">
<propertyname="businessInterface"
value="samples.HelloServiceBI">
<propertyname="jndiTemplate">
<refbean="jndiTemplate">
<property>
</bean>
</jsr181:pojo>
</jsr181:endpoint>
</jsr181:endpoints>
</jsr181:component>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
<beanid="jndiTemplate"
class="org.springframework.jndi.JndiTemplate">
<propertyname="environment">
<props>
<propkey="java.naming.factory.initial">
weblogic.jndi.WLInitialContextFactory
</prop>
<propkey="java.naming.provider.url">
t3://localhost:7001
</prop>
</props>
</property>
</bean>
</beans>
Wewillnowdiscussthiscodesectionbysection.
JNDIcontextisthestartingpointingettingareferencetoanEJBresource.Inthepreviousstep,wehavedeployedourEJBservicetotheWeblogicserver.ToaccessWebLogic'sJNDItree,youneedtoestablishastandardJNDIInitialContextrepresentingthecontextrootoftheserver'sdirectoryservice.Forthis,thePROVIDER_URLpropertyspecifiestheURLoftheserver,whoseJNDItreewewanttoaccessandtheINITIAL_CONTEXT_FACTORYpropertycontainsthefullyqualifiedclassnameofWebLogic'scontextfactory.
IfyouneedtoaccessWebLogic'sJNDItree,itisadvisedtoestablishthecontextusingtheclassnameweblogic.jndi.WLInitialContextFactory,sothatwecanusetheWeblogicspecifict3protocolwhichisoptimizedforaccessingservices.Wedefinethesedetailsbyconfiguringtheorg.springframework.jndi.JndiTemplate
bean.
ThenextstepistodefineourPOJOclass.ThePOJOclasshereisnotaserviceclass,butaclient-sideproxytotheremoteEJBservice.There'salotofbackendplumbinghappeningherewhenweuseSimpleRemoteStatelessSessionProxyFactoryBe
an,courtesyoftheSpringAOPframework.ThePOJObeandefinitioncreatesaproxyfortheremotestatelessEJB,whichimplementsthebusinessmethodinterface.TheEJBremotehomeiscachedonstartup,sothere'sonlyasingleJNDIlookup.EachtimetheEJBisinvoked,theproxyinvokesthecorrespondingbusinessmethodontheEJB.AllthecontextdetailsnecessaryforcontactingtheserverareretrievedfromthepreviousjndiTemplatebean.
OnceourPOJObeanisready,itisjustamatterofwrappingthatupintheservicemix-jsr181asshownintheconfigurationabove.Whenyouconfigurethejsr181:endpoint,youcanalsospecifytheserviceInterface.Thiswillholdtheclassnameoftheinterfacetoexposeasaserviceandthisabstractionwillhelpthebindingtobeexposedinstandardways(usingWSDL),whichwewillexploreshortly.
WewillappreciatethefactthatEJBcomponentsareremotable,buttheynormallyexposebinaryinterfaces.Binaryprotocolsarenotplatformagonistic,noraretheyfirewall-friendly.Hence,EJBcomponentsarenormallypreferredonaLANwherewehaveperfectcontrolofthenetwork,sothatnothinghindersmarshallingbytesacrossdomains.Ifwehavetomakethemfirewall-friendly,wecantunnelthemthroughadifferentprotocol,whichbyitselfisfirewall-friendly.Weblogicandothersimilarserversprovideeasytunnelingoptionsbutstillthemechanismisnotastandardapproach.ThesecondmethodistowrapEJBwithwebservices.Thisisalsomadeeasynowadaysbyapplicationservers,itisjustamatterofenablingoptionsduringdeploymenttime.
WhenwehaveanESB,anoptionavailabletousistoleveragetheprotocolorformatconversioncapabilityoftheESBtomakeEJBinvocationsfirewall-friendly.ServiceMixservicemix-httpisexactlywhatweneedhere.Byconnectingaservicemix-httpchannelinserialandinfrontoftheservicemix-jsr181,wecanmaketheEJBcomponentserviceavailableoutsidethefirewallasanormalwebservice!Whatmore,wecanevenrunourentirenormalwebservicesclienttoolkittoretrieveWSDL,andthentogenerateclient-sideproxyclassessothatitiseasytoinvokefunctionality.ThetargetServiceandthetargetEndpointattributesofservicemix-httppointbacktotherespectivenamesoftheservicemix-jsr181,sothatweconnectthecomponentstogether.
StepThree—DeployandInvokeEJBBindinginServiceMixForthissamplewewillfollowthelightweightdeploymentmodel.
ch08\BindEjb\02_BindInEsbcontainsallthenecessaryfilesforbinding,building,anddeployingtheartifactsintoaServiceMixcontainer.TobuildtheESBbindingcodebaseanddeploythesample,changedirectorytoch08\BindEjb\02_BindInEsb,whichcontainsatop-levelbuild.xmlfile.Thenotablesectioninthebuild.xmlisshowninthefollowingcode:
<targetname="copy-components"depends="init"
description="Buildcomponents">
<copytodir="${servicemix.home}/lib/optional"
overwrite="true">
<filesetdir="${client.classes.dir}"
includes="sample_statelessSession_client.jar">
<copy>
<copytodir="${servicemix.home}/lib/optional"
overwrite="true">
<filesetdir="${wl.home}/server/lib"
includes="weblogic.jar">
<copy>
</target>
Here,wefirstcopytheEJBclientjarfromtheWeblogicdirectorytoServiceMix'soptionallibraryfolder.Otherthanthis,wedon'thaveanyexplicitreferraltoEJBclassesintheServiceMixbindingabove.Whatyou'reseeingisSpring'ssuccessinabstractingawaytheclientsideoftheclunkyEJB
contract.However,thehomeandremoteinterfacesarestillrequired—Springisusingthemunderthehood,justasyouwouldifyouhadtowritetheJNDIlookup,EJBhome,andcreatecallsyourself.WhatSpringisdoingbehindthescenesismakingaJNDIlookupforthehome,thencallingthecreate()methodonthehomeandenablingyoutoworkwiththat.ThatiswhywerequiretheEJBclientjarintheclasspath.
Wehaveseenpreviously,howweconfiguredjndiTemplatebyexplicitlyreferringtheweblogic.jndi.WLInitialContextFactory.Thisisincludedinweblogic.jarandhenceweincludethatjarintheServiceMix'soptionallibraryfoldertoo.IncaseyouareusingadifferentEJBserverandyouuseadifferentjava.naming.factory.initialclass,thenincludetherespectivejarsinServiceMix'soptionallibraryfoldertoo.Tobuild,executeantasshowninthefollowingcode:
cdch08\BindEjb\02_BindInEsb
ant
Now,bringuptheServiceMixcontainerbyexecutingtheservicemix.xmlfilecontainedinthesamefolder.
%SERVICEMIX_HOME%/bin/servicemixservicemix.xml
TheClient.htmlfileprovidedagaininthesamefoldercanbeusedtosendmessagestotestthedeployedservice.
StepFour—AccessWSDLandGenerateAxis-basedStubstoAccessEJBOutsideFirewallAsdiscussedabove,wecannowaccesstheWSDLauto-generatedbyServiceMixoutoftheearlierEJBbinding.TheWSDLcanbeaccessedbypointingyourbrowsertothefollowingURL:
http://localhost:8192/Services/HelloWebSer
vice/?wsdl
or
http://localhost:8192/Services/HelloWebSer
vice/main.wsdl
TheWSDLisreproducedinthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:ns1="http://io.java"
xmlns:soap11="http://schemas.xmlsoap.org/soap/
envelope/"
xmlns:soap12="http://www.w3.org/2003/05/
soap-envelope"
xmlns:soapenc11="http://schemas.xmlsoap.org/soap/
encoding/"
xmlns:soapenc12="http://www.w3.org/2003/05/
soap-encoding"
xmlns:tns="http://binildas.com/esb/bindejb"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/
soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://binildas.com/esb/bindejb">
<wsdl:types>
<xsd:schemaattributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://io.java"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexTypename="IOException">
<xsd:schema>
<xsd:schemaattributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://binildas.com/esb/bindejb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:elementname="hello">
<xsd:complexType>
<xsd:sequence>
<xsd:elementmaxOccurs="1"minOccurs="1"
name="in0"nillable="true"type="xsd:string">
<xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:elementname="helloResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:elementmaxOccurs="1"minOccurs="1"
name="out"nillable="true"type="xsd:string">
<xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:elementname="IOException"
type="ns1:IOException">
<xsd:schema>
</wsdl:types>
<wsdl:messagename="helloResponse">
<wsdl:partelement="tns:helloResponse"
name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:messagename="IOException">
<wsdl:partelement="tns:IOException"
name="IOException">
</wsdl:part>
</wsdl:message>
<wsdl:messagename="helloRequest">
<wsdl:partelement="tns:hello"name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:portTypename="jsrEjbEPPortType">
<wsdl:operationname="hello">
<wsdl:inputmessage="tns:helloRequest"
name="helloRequest">
</wsdl:input>
<wsdl:outputmessage="tns:helloResponse"
name="helloResponse">
</wsdl:output>
<wsdl:faultmessage="tns:IOException"
name="IOException">
</wsdl:fault>
</wsdl:operation>
</wsdl:portType>
<wsdl:bindingname="HelloServiceBIBinding"
type="tns:jsrEjbEPPortType">
<wsdlsoap:bindingstyle="document"
transport="http://schemas.xmlsoap.org/soap/
http">
<wsdl:operationname="hello">
<wsdlsoap:operationsoapAction="">
<wsdl:inputname="helloRequest">
<wsdlsoap:bodyuse="literal">
<wsdl:input>
<wsdl:outputname="helloResponse">
<wsdlsoap:bodyuse="literal">
<wsdl:output>
<wsdl:faultname="IOException">
<wsdlsoap:faultname="IOException"use="literal">
<wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:servicename="HelloServiceBIService">
<wsdl:portbinding="tns:HelloServiceBIBinding"
name="HelloServiceBI">
<wsdlsoap:address
location="http://localhost:8192/Services/
HelloWebService/">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
WewillnowuseApacheAxistoolstoauto-generateclient-sidestubsandbindingclassesusingwhichwecanwriteasimpleJavaclientclass,toaccesstheservicethroughtheHTTPchannel.Whenwedothis,theinterestingpointisthatweareaccessinganEJBservicebehindthescenes,butusingtheSOAPformatforrequestandresponse,thattoothroughafirewall-friendlyHTTPchannel.TheAxisclientclassesareplacedinthedirectorych08\BindEjb\03_AxisClient.
Todothat,wehavetousethewsdl2javaanttask.Letusfirstdeclarethetaskdefinitionandexecutethattasktogeneratestubclasses,asshowninthefollowingcode:
<taskdefname="wsdl2java"
classname="org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask"
loaderref="axis">
<classpathrefid="classpath">
<taskdef>
<targetname="wsdl2java">
<javaclassname="org.apache.axis.wsdl.WSDL2Java"
fork="true"
failonerror="true">
<argvalue="-o">
<argvalue="${src}">
<argvalue="-x">
<argvalue="http:/io.java">
<argvalue="HelloWebService.wsdl">
<classpath>
<pathrefid="classpath"/>
<pathelementlocation="${build}">
<classpath>
</java>
</target>
ThetaskwillextractthedetailsfromtheWSDLandgeneratethefollowingclient-sideartifactsinthech08\BindEjb\03_AxisClient\srcfolder:
com\binildas\esb\bindejb\HelloServiceBIBindingStub.java
com\binildas\esb\bindejb\HelloServiceBIService.java
com\binildas\esb\bindejb\HelloServiceBIServiceLocator.java
com\binildas\esb\bindejb\JsrEjbEPPortType.java
RememberthattheaboveWSDLfromwheretheAxistoolgeneratedtheclient-sideartifactsis,infact,theWSDLretrievedfromtheServiceMixESB.TheClientjavaclasscanbewrittenagainstthesegeneratedfilesasfollows:
publicclassClient
{
privatestaticStringwsdlUrl=
"http://localhost:8192/
Services/HelloWebService/main.wsdl";
privatestaticStringnamespaceURI=
"http://binildas.com/esb/bindejb";
privatestaticStringlocalPart=
"HelloServiceBIService";
protectedvoidexecuteClient(String[]args)throws
Exception
Exception
{
HelloServiceBIServicehelloServiceBIService=
null;
JsrEjbEPPortTypejsrEjbEPPortType=null;
if(args.length==3)
{
helloServiceBIService=new
HelloServiceBIServiceLocator(args[0],new
QName(args[1],args[2]));
}
else
{
helloServiceBIService=new
HelloServiceBIServiceLocator(wsdlUrl,new
QName(namespaceURI,localPart));
}
jsrEjbEPPortType=
helloServiceBIService.getHelloServiceBI();
log("ResponseFromServer:"+
jsrEjbEPPortType.hello("Binil"));
}
publicstaticvoidmain(String[]args)throws
Exception
{
Clientclient=newClient();
client.executeClient(args);
}
}
TobuildtheentireAxisclientcodebase,assumingthatboththeEJBserverandtheServiceMixcontainerisupandrunning,changedirectorytoch08\BindEjb\03_AxisClient,whichcontainsatop-levelbuild.xmlfile.Executeantasshowninthefollowingcommands:
cdch08\BindEjb\03_AxisClient
ant
ThiswillgeneratetherequiredAxisclient-sidestubsandcompiletheclientclasses.Nowtoruntheclient,executethefollowingcommand:
antrun
ReconcilingEJBResourcesThischapterdemonstratedhowtoengineerwithServiceMix,hencewecanconsiderEJBcomponentservicesequivalenttonormalwebservicessothesamerulescanbeappliedfromaconsumerperspective.Thiswillhavegreaterimpactintoday'ssolutioninfrastructure.Thisisbecauseinthelastonedecadeorso,wesawtheriseofEJBcomponent-basedprogramming.Settingaside(if)anydrawbacks,EJBgaveusalotofsupportforcrosscuttingconcernsliketransactionmanagementandinstancepooling.Forthesamereason,lotsofsolutionartifactsarestillavailableandremaininghostedintheformofEJBservices.UsinganESB,wearenolongerforcedtothrowawayallthoseinvestments,insteadleveragetheminaservicesecosystemenvironment.IamsureIwillhaveaneasytimeconvincingmyCTOthatIdon'tneedtoscrapallmyEJBinvestments,insteadIcanreusetheminthebestpossiblemanner.Ihopeyouwillalsoenjoythesame.
SummaryESBasaservicefabricsupportsintegratingmultipleservicesandcomponenttypes.Hence,fromtheconsumerperspective,theyseeapureservicesinterfacewithallSOAqualities.ThischapterdemonstratedhowthesameprincipleshelpedustoexposeanEJBserviceasafirewall-friendlywebservice.ThenotablethinghereistheeasewithwhichanESBframeworkdoesthis—andthatiswheretherighttoolswillhelptosolveevennontrivialproblemseasily.So,insteadofholdingtheESBhammerandlookingateveryITproblemasanail,useESBandJBItosolveappropriateintegrationproblemsfollowingSOIguidelinesalone.MostcomponentframeworksavailabletodayallowevenPOJOcomponentstobeexposedasservicessothattheycanbeconsumedremotely.ThisisalightweightapproachcomparedtothetraditionalEJBprogrammingparadigm.
Inthenextchapter,wewilllookintothisconcepttounderstandhowwecanexposeanannotatedPOJOasservicesintheESB.
Chapter9.POJOBindingUsingJSR181Firstthingsfirstandsimplethingsforemost!IshouldhaveintroducedthePOJObindingasthefirstexampleduetothesimplicityinthename"POJO".However,thereisanothercomponentassociatedwiththePOJObinding,whichistheservicemix-jsr181componentthatweneedtolearntogether.ThisiswhywedelayedthePOJObindinguntilnow.Wecannowmoveon.
Wewillcoverthefollowinginthischapter:
OverviewonPOJO
JSR181andservicemix-jsr181component
APOJObindingsampledemonstratingPOJOasservices
AsecondsampletodemonstrateaccessingtheJBIbusdirectlyatprogrammingAPI-level
POJOChristopherRichardsoninhiscoverstory"WhatIsPOJOProgramming"says:
Fortunately,there'snowamuchbetterwaytobuildEnterpriseJavaapplications:PlainOldJavaObjects(POJOs),which
areclassesthatdon'timplementinfrastructureframework-specificinterfaces,andnon-invasiveframeworkssuchasSpring,Hibernate,JDO,andEJB3,whichprovideservicesforPOJO.
WhatarePOJOsPOJOsdependonbasicorcoreJavaanddon'timplementanyotherAPI's.Theyneithercontainanyframeworkspecificcallbackmethods,nordependonanyexternalmethods,whichtheyneedtocall.Instead,anythird-partyframeworkcanmakeuseofaPOJOclassandexposeitorutilizeitintheirownway.Forexample,anO-RmappingframeworkcanuseaPOJOmodelclassandpersistinarelationaldatabase.Similarly,aservicegenerationframeworkcanexposeallthepublicmethodsinaPOJOserviceclassasservices.ATOassemblercangetandsetvaluesfromaPOJOTOtocreateacoarsergrained,POJOTOgraph.
ComparingPOJOwithotherComponentsPOJOs,beingsignificantlylightweight,willhavetheirownadvantagesanddisadvantageswhencomparedtoothercounterpartcomponentssuchasEJBsandservlets.
ThemainadvantageisthatthePOJOscanbedeployedandruninthesimplestoftheJavaruntimesavailable,andnothingpreventsyoufromdeployingthemintoafull-fledged
containerinfrastructure.Thiswillhelpyoutoleveragethebestofboththeworlds—thelightweightdeploymentmodelandthefull-fledgedcontainerinfrastructurefunctionalities.
Atthesametime,thedownsideofPOJOsisthattheyarenotremotable.Remotingisthemechanismbywhichfunctionalitycanbeaccessedfromaremotenode,throughanetwork.EJB,servlet,andJSP.Thesecomponentsareinherentlyremotable.HowinterestedwouldareaderbeifwecouldmakeaPOJOremotable—withoutmuchhassle?Holdon,wewilldothatinthischapter.
ServiceMixservicemix-jsr181ServiceMix'sservicemix-jsr181componentisbuiltbasedontheJSR181specification.
JSR181JSR181definesanannotatedJavasyntaxforprogrammingwebservicesandisbuiltontheJavaLanguageMetadatatechnology(JSR175),toprovideaneasywaytousesyntaxtodescribewebservicesatthesource-code-levelfortheJ2EEplatform.ItaimstomakeiteasyforaJavadevelopertodeveloptheserverapplicationsthatconformbothtobasicSOAPandWSDLstandards.TheWSMfortheJavaplatformisbuiltupontheJSR175andhencerequiresaJDKinstallationsupportingJavametadata.
servicemix-jsr181servicemix-jsr181componentisaJBIstandardSE.ItcanexposeannotatedPOJOasservices.servicemix-jsr181internallyusesXFiretoexposePOJOsasservices.servicemix-jsr181linkstheJBIchanneltoXFiretransportusingthefollowingsteps:
servicemix-jsr181firstcreatesaDefaultXFireandregisterstheJbiTransporttothetransportmanagerofXFire.
ThenitusesXFire'sObjectServiceFactorytocreateanXFireservice.
servicemix-jsr181thenconfigurestheserviceandregistersitintheXFireserviceregistry.
TheabovestepslinktheJBIchanneltoXFiretransport.However,allthesearethebackgroundplumbingabstractedoutbytheservicemix-jsr181,sothatthedeveloperwon'tseeallthesecomplexities.WehavealreadydiscussedthepowerofXFireandworkedoutafewsamples.AgainwewillleverageXFire,butnowintheformofastandardJBIcomponentitself,forbinding.
AspertheServiceMixdocumentation,servicemix-jsr181supportsthefollowingfeatures:
noannotations
jsr181annotations
commons-attributesannotations
aegisbinding
jaxb2binding
xmlbeansbinding
wsdlautogeneration
MTOMorattachmentssupport
servicemix-jsr181DeploymentXBean-baseddeploymentcanbeusedtodeployservicemix-jsr181,bothintheproviderandconsumerroles.
Thefirststepistodeclarethenecessaryjsr181namespaceelements,shownasfollows:
<beans
xmlns:jsr181="http://servicemix.apache.org/jsr181/1.0"
xmlns:test="http://binildas.com/esb/jsrpojo">
</beans>
WhetheritisasimplePOJObindingoranEJBbinding,weneedtoincludealltherequiredinterfaceandimplementationclassestotherespectiveclasspaths.WecandothisbyincludingtherequiredclassfilesorjararchivesintheSUandreferencethemusingthefollowingtagsinthexbean.xmlconfigurationfile:
<classpath>
<location>.</location>
</classpath>
ThepathvaluespecifiedforthelocationtagisrelativetotheunzippedSU.Forexample,ifJsrBindistheSUname
andwehaveaclasscalledtest.EchoService,thenweneedtopackagetheclasswithinthefoldertest,relativetothetop-levelofJsrBindarchive.Similarly,youcanalsoaddJavaarchives(.jar)containingclassfilesbyexplicitlyspecifyingthemasfollows:
<classpath>
<location>lib/test.jar</location>
</classpath>
servicemix-jsr181Endpointservicemix-jsr181endpointscanbeconfiguredinmultipleformatsusingSpringbeanconfigurations.Themultipleformatsarelistedinthefollowinglist:
1. <jsr181:endpointannotations="none"service="test:helloService">
<jsr181:pojo>
<beanclass="samples.HelloServicePojo">
</bean>
</jsr181:pojo>
</jsr181:endpoint>
2. <beanid="helloPojo"class="samples.HelloServicePojo"/>
<jsr181:endpointpojo="#helloPojo"/>
3. <jsr181:endpointpojoClass="samples.HelloServicePojo"annotations="none"/>
POJOBindingSampleFromtheentirediscussionwehavehadinthischapter,letusbuildaPOJObindingsample.Thecodebaseforthesampleislocatedinthefolderch09\Jsr181BindPojo.
SampleUseCaseInthisPOJObindingsampleusecase,wewillintegratePOJOcomponentswithServiceMixJBIcomponentssothattheywilltakepartinmessageexchangeswiththeNMR.ThePOJOclassusedinthesamplecanbereplacedwithyourcodeperformingtransformation,dependinguponyourbusinessscenario.Inoursamplehere,wewilluseasetofcomponentsintegratedintheESBasshowninthefollowingfigure:
AsimplePOJOclassaloneisenoughtodemonstratethebindingsample.However,wewillalsoexposePOJOasanormalwebservice,accessWSDL(yes,really),andrunanAxisclientagainsttheWSDLtogenerateclientstubstoaccessthePOJOserviceremotely.Tofacilitateallthis,wewillfirstintegrateourPOJOclass(HelloServicePojo)withaservicemix-jsr181component.Nowasweknow,HTTPisaneasyandsimplechanneltoaccessservices.Hence,letusalsointegrateaservicemix-httpintheconsumerroletotheNMRsothatourtestclientscanhaveaneasychanneltosendmessages.Thecomponentsareintegratedasshownintheabovefigure.Whentheclientsendsamessage,
themessage-flowacrosstheNMRthroughvariousJBIcomponentsaremarkedbynumbersinsequence.
POJOCodeListingLetusfirstdefineaBI.NotethattheBIisnotmandatoryforPOJObinding,buthereweareusingbest(interface-basedprogramming)practices.Thus,HelloServiceBIistheBI.
TheinterfaceHelloServiceBIisshowninthefollowingcode:
publicinterfaceHelloServiceBI
{
Stringhello(Stringphrase)throws
java.io.IOException;
}
InJavaRMIorEJBprogramming,thebusinessmethodsareusuallymarkedtothrowajava.rmi.RemoteException.WecangeneralizethisexceptionscenariobyreplacingtheRemoteExceptionwiththejava.io.IOException.WewillfollowthisconventionbymarkingourbusinessmethodsasthrowingIOException.Thereisabsolutelynothingwrongifwedon'tmentiontheexceptioninthethrowsclausetoo,foroursampleshere.Now,HelloServicePojowillimplementtheaboveinterface.Moreoverasyoucansee,thisclassqualifiestobeahundredpercentPOJOclass.
TheHelloServicePojoclassisshownasfollows:
publicclassHelloServicePojoimplements
HelloServiceBI
{
privatestaticlongtimes=0;
publicStringhello(Stringphrase)
{
System.out.println("HelloServiceBean.hello{"+
(++times)+"}");
return"FromHelloServiceBean:HELLO!!Youjust
said:"+phrase;
}
}
XBean-basedPOJOBindingUsingXBean,wewillnowconfigurethePOJOtobedeployedontothestandardservicemix-jsr181JBIcomponent.
Thexbean.xmlisasshowninthefollowingcode:
<beans
xmlns:jsr181="http://servicemix.apache.org/jsr181/1.0"
xmlns:test="http://binildas.com/esb/jsrpojo">
<classpath>
<location>.</location>
</classpath>
<jsr181:endpointannotations="none"
service="test:helloService"
serviceInterface="samples.HelloServiceBI">
<jsr181:pojo>
<beanclass="samples.HelloServicePojo">
</bean>
</jsr181:pojo>
</jsr181:endpoint>
</jsr181:endpoint>
</beans>
TheaboveconfigurationwillexposeHelloServicePojoasaserviceontheJBIbus,sothatfromnowonanyJBIcomponentcanexchangemessageswiththiscomponent.
Toeasilydemonstrateaccessingtheservice,wewillalsobindtheHTTPchanneltotheJBIbus.ThenasimpleHTMLclientcaninteractwiththebussendingthemessages.TheHTTPbindingisshowninthefollowingcode:
<beans
xmlns:http="http://servicemix.apache.org/http/1.0"
xmlns:test="http://binildas.com/esb/jsrpojo">
<classpath>
<location>.</location>
</classpath>
<http:endpointservice="test:PojoBindService"
endpoint="PojoBindService"role="consumer"
targetService="test:helloService"
locationURI="http://localhost:8081/services/
PojoBindService"soap="true"
defaultMep="http://www.w3.org/2004/08/wsdl/
in-out">
<beans>
DeploymentConfigurationFordeployment,wewillpackagetherelevantartifactsfortheJSRPOJObindingintoaZIParchivenamedjsrbind-su.zip.Weneedtodeploythisarchiveontotheservicemix-jsr181componentandthatisdonethrough
thejbi.xmlasshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<jbixmlns="http://java.sun.com/xml/ns/jbi"
version="1.0">
<service-assembly>
<identification>
<name>JsrBindAssembly</name>
<description>JsrBindService
Assembly</description>
</identification>
<service-unit>
<identification>
<name>JsrBind</name>
<description>JsrBindServiceUnit</description>
</identification>
<target>
<artifacts-zip>jsrbind-su.zip</artifacts-zip>
<component-name>servicemix-jsr181</component-
name>
</target>
</service-unit>
</service-assembly>
</jbi>
Assaidearlier,wealsohaveaHTTPbindingtoeasilyaccessthePOJOservice.Hence,wehaveanotherjbi.xml,whichwillspecifyhowtodeploytheHTTPartifactsontotheservicemix-httpstandardJBIcomponent.Thisisshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<jbixmlns="http://java.sun.com/xml/ns/jbi"
version="1.0">
<service-assembly>
<identification>
<name>HttpBindAssembly</name>
<name>HttpBindAssembly</name>
<description>HttpBindService
Assembly</description>
</identification>
<service-unit>
<identification>
<name>JsrProxy</name>
<description>HttpBindServiceUnit</description>
</identification>
<target>
<artifacts-zip>httpbind-su.zip</artifacts-zip>
<component-name>servicemix-http</component-name>
</target>
</service-unit>
</service-assembly>
</jbi>
DeployingandRunningtheSampleAsthefirststepandifyouhaven'tdoneitbefore,editexamples.PROPERTIESprovidedalongwiththecodedownloadforthischapterandchangethepathstheretomatchyourdevelopmentenvironment.ThecodedownloadforthischapteralsoincludesaREADME.txtfile,whichgivesdetailedstepstobuildandrunthesamples.
Tobuildtheentirecodebaseanddeploythesample,changedirectorytoch09\Jsr181BindPojo,whichcontainsatop-levelbuild.xmlfile.Executeantasshowninthefollowingcommand:
cdch09\Jsr181BindPojo
ant
Now,bringuptheServiceMixcontainerbyexecutingtheservicemix.xmlfilecontainedinthesamefolder.
%SERVICEMIX_HOME%/bin/servicemixservicemix.xml
TheClient.htmlprovidedagaininthesamefoldercanbeusedtosendmessagestotestthedeployedservice.
AccessWSDLandGenerateAxis-basedStubstoAccessPOJORemotelyYoucannowaccesstheWSDLauto-generatedbyServiceMixoutoftheearlierPOJObinding.TheWSDLcanbeaccessedbypointingyourbrowsertothefollowingURL:
http://localhost:8081/services/PojoBindSer
vice/?wsdl
or
http://localhost:8081/services/PojoBindSer
vice/main.wsdl
EventhoughtheWSDLherehasnothingfancyaboutit,theimportantaspectisthatthisWSDLisauto-generatedbytheJBIbus,outoftheserviceInterface(theBI,discussedearlier)configuredinthejsr181:endpoint.LetusmakesurethattheWSDLisverysimilartoanyWSDLwegenerate
outfromanormalwebservice.LetuslisttheWSDLhere:
<?xmlversion="1.0"encoding="UTF-8"?>
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:ns1="http://io.java"
xmlns:soap11="http://schemas.xmlsoap.org/soap/
envelope/"
xmlns:soap12="http://www.w3.org/2003/05/
soap-envelope"
xmlns:soapenc11="http://schemas.xmlsoap.org/soap/
encoding/"
xmlns:soapenc12="http://www.w3.org/2003/05/
soap-encoding"
xmlns:tns="http://binildas.com/esb/jsrpojo"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/
soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://binildas.com/esb/jsrpojo">
<wsdl:types>
<xsd:schemaattributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://binildas.com/esb/jsrpojo"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:elementname="hello">
<xsd:complexType>
<xsd:sequence>
<xsd:elementmaxOccurs="1"minOccurs="1"
name="in0"nillable="true"type="xsd:string">
<xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:elementname="helloResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:elementmaxOccurs="1"minOccurs="1"
name="out"nillable="true"type="xsd:string">
<xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:elementname="IOException"
type="ns1:IOException">
<xsd:schema>
<xsd:schemaattributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://io.java"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexTypename="IOException">
<xsd:schema>
</wsdl:types>
<wsdl:messagename="helloRequest">
<wsdl:partelement="tns:hello"name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:messagename="helloResponse">
<wsdl:partelement="tns:helloResponse"
name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:messagename="IOException">
<wsdl:partelement="tns:IOException"
name="IOException">
</wsdl:part>
</wsdl:message>
<wsdl:portTypename="helloServicePortType">
<wsdl:operationname="hello">
<wsdl:inputmessage="tns:helloRequest"
name="helloRequest">
</wsdl:input>
<wsdl:outputmessage="tns:helloResponse"
name="helloResponse">
</wsdl:output>
<wsdl:faultmessage="tns:IOException"
name="IOException">
</wsdl:fault>
</wsdl:operation>
</wsdl:portType>
<wsdl:bindingname="PojoBindServiceBinding"
type="tns:helloServicePortType">
<wsdlsoap:bindingstyle="document"
transport="http://schemas.xmlsoap.org/
soap/http">
<wsdl:operationname="hello">
<wsdlsoap:operationsoapAction="">
<wsdl:inputname="helloRequest">
<wsdlsoap:bodyuse="literal">
<wsdl:input>
<wsdl:outputname="helloResponse">
<wsdlsoap:bodyuse="literal">
<wsdl:output>
<wsdl:faultname="IOException">
<wsdlsoap:faultname="IOException"use="literal">
<wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:servicename="PojoBindService">
<wsdl:portbinding="tns:PojoBindServiceBinding"
name="PojoBindService">
<wsdlsoap:address
location="http://localhost:8081/
services/PojoBindService/">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
WewillnowusetheApacheAxistoolstoauto-generatetheclient-sidestubsandthebindingclassesusingwhichwecanwriteasimpleJavaclientclasstoaccesstheservicethroughaHTTPchannel.TheAxisclientclassesareplacedinthedirectorych09\Jsr181BindPojo\03_AxisClient.
Todothat,wehavetousethewsdl2javaanttask.Letusdeclarethetaskdefinitionandexecutethattasktogeneratethestubclasses.
<taskdefname="wsdl2java""
classname="org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask"
loaderref="axis">
<classpathrefid="classpath">
<taskdef>
<targetname="wsdl2java">
<javaclassname="org.apache.axis.wsdl.WSDL2Java"
fork="true"failonerror="true">
<argvalue="-o">
<argvalue="${src}">
<argvalue="-x">
<argvalue="http:/io.java">
<arg
value="http:/localhost:8081/services/PojoBindService/
main.wsdl">
<classpath>
<pathrefid="classpath">
<pathelementlocation="${build}">
<classpath>
</java>
</target>
ThetaskwillextractWSDLfromthespecifiedlocationandgeneratethefollowingclient-sideartifacts:
com\binildas\esb\jsrpojo\HelloServicePortType.java
com\binildas\esb\jsrpojo\PojoBindService.java
com\binildas\esb\jsrpojo\PojoBindServiceBindingStub.java
com\binildas\esb\jsrpojo\PojoBindServiceLocator.java
TheClientJavaclasscanbewrittenagainstthesegeneratedfilesasfollows:
publicclassClient
{
privatestaticStringwsdlUrl=
"http://localhost:8081/services/
PojoBindService/main.wsdl";
privatestaticStringnamespaceURI=
"http://binildas.com/esb/jsrpojo";
privatestaticStringlocalPart=
"PojoBindService";
protectedvoidexecuteClient(String[]args)throws
Exception
{
PojoBindServicepojoBindService=null;
HelloServicePortTypehelloServicePortType=null;
if(args.length==3)
{
pojoBindService=new
PojoBindServiceLocator(args[0],new
QName(args[1],args[2]));
}
else
{
pojoBindService=new
PojoBindServiceLocator(wsdlUrl,new
QName(namespaceURI,localPart));
}
helloServicePortType=
pojoBindService.getPojoBindService();
log("ResponseFromServer:"+
helloServicePortType.hello("Binil"));
}
publicstaticvoidmain(String[]args)throws
Exception
{
Clientclient=newClient();
client.executeClient(args);
}
}
TobuildtheentireAxisclientcodebase,assumingthatServiceMixisupandrunning,changedirectorytoch09\Jsr181PojoAccessBus\04_AxisClient,whichcontainsatop-levelbuild.xmlfile.Executeantasfollows:
cdch09\Jsr181PojoAccessBus
ant
ThiswillgeneratetherequiredAxisclient-sidestubsandcompiletheclientclasses.Nowtoruntheclient,executethefollowingcommand:
antrun
AccessingJBIBusSampleIntheprevioussample,wehaveseenhowtobindaPOJOtoJBIandaccesstheserviceagainusingthestandardwebserviceaccessmechanisms.Occasionally,yourcomponentsmayalsowanttoaccesstheJBIbusdirectlyatprogrammingAPI-level,andwecandothatusingthenumerousAPIsprovidedbyServiceMixandJBI.
ThepreferredmechanismtoaccessJBIfromyourcomponentistofirstgettheComponentContextimplementationandfromtheretraversetheotherJBIAPIs.
<jsr181:endpointannotations="none"
service="some:Service"
serviceInterface="some.Interface">
<jsr181:pojo>
<beanclass="some.Pojo">
<propertyname="context"ref="context">
<bean>
</jsr181:pojo>
</jsr181:endpoint>
Correspondingly,wewillnowhaveourPojo(Oh,yes;ourPOJOsaregettingbulkierhere!)classintowhichtheJBIcontainercaninjectareferenceoftheComponentContext.Thepojoclassisreproducedinthefollowingcode:
publicclassPojo
{
privatejavax.jbi.component.ComponentContext
context;
publicvoid
setContext(javax.jbi.component.ComponentContext
context)
{
this.context=context;
}
}
ComponentContextistheJBIAPIusingwhichwecanaccesstheunderlyingDeliveryChannel.Thisisshowninthefollowingcode:
publicinterfaceComponentContext
{
publicDeliveryChannelgetDeliveryChannel()throws
MessagingException;
MessagingException;
}
DeliveryChannelcanbeusedtosendmessagestotheJBIbus.ItistobenotedthatonlysendSync()isallowedforactiveJBIexchanges(butyouhavetousesend()forDONEorERRORstatusexchanges).Thisisshowninthefollowingcode:
publicinterfaceDeliveryChannel
{
publicMessageExchangeaccept()throws
MessagingException;
publicvoidsend(MessageExchangeexchange)throws
MessagingException;
publicbooleansendSync(MessageExchangeexchange)
throwsMessagingException;
publicbooleansendSync(MessageExchangeexchange,
longtimeout)throwsMessagingException;
}
SampleUseCaseforAccessingJBIBusWewillhaveanotherfullsampleforPOJObindingtodemonstratehowtoaccesstheJBIbusfromwithinaPOJO.Asdescribedabove,wecanuseComponentContexttoaccesstheDeliveryChanneltosendmessagestotheJBIbus.AnotherwaytointeractwiththeJBIbusistousetheclientAPI.LetusdefineasampleusecasetoaccesstheJBIbus.
Wewillhavethefollowingcomponentstoimplementthesampleusecase:
Client
HTTPbinding
JSRPOJOBridge
JSRPOJODestination
Thesecomponentsareintegratedasshowninthefollowingfigure.Whentheclientsendsamessage,themessageflowthroughtheNMRthroughvariousJBIcomponentsismarkedbynumbersinsequence.
Theabovecomponentswillexchangemessagesinthefollowingsequence:
1. ClientsendsmessagetoHTTPbinding.
2. HTTPbindingroutesmessagestodestinationthroughJBIbus.
3. JSRPOJOBridgebeingthedestinationfortheabovemessage,willacceptthemessage.
4. TheJSRPOJOBridgewillperformthefollowingstepstosendthenextmessagetotheJBIbus.
1. ItfirstcreatesareferenceofServiceMixClient.
ServiceMixClientclient=new
ServiceMixClientFacade(this.context);
2. ItthencreatesaQNametoreferthedestinationservice.
QNameservice=new
QName("http://binildas.com/esb/
jsrpojo","destinationHelloService");
3. UsingtheaboveServiceMixClientandtheservicereference,itthencreatesanEndpointResolver.
EndpointResolverresolver=
client.createResolverForService(service);
4. Now,wecansendthemessagetotheJBIbususingtheServiceMixClient.
client.send(resolver,null,null,
messageToDespatch);
5. Now,destinationHelloServiceistheservicepointingtoJSRPOJODestination.So,themessagefromtheJBIbuswillbeacceptedbyJSRPOJODestination.
Thefollowingfigureshowstheabovesequencesofevents:
SampleCodeListingThereisnotmuchdifferenceinthecodethanwhatwehaveseenintheprevioussample,buttheBridgeHelloServicePojoclasswillbelistedasfollows,todiscussafewpoints:
publicclassBridgeHelloServicePojoimplements
BridgeHelloServiceBI
{
privateComponentContextcontext;
publicvoidsetContext(ComponentContextcontext)
{
this.context=context;
}
publicStringbroker(Stringphrase)
{
try
{
send(phrase);
}
catch(JBIExceptionjbiException)
catch(JBIExceptionjbiException)
{
jbiException.printStackTrace();
returnjbiException.getMessage();
}
return"Success";
}
privatevoidsend(Stringmessage)throws
javax.jbi.JBIException
{
System.out.println("BridgeHelloServicePojo.1.
message:"+message);
ServiceMixClientclient=new
ServiceMixClientFacade(this.context);
QNameservice=newQName(namespaceURI,
localPart);
EndpointResolverresolver=
client.createResolverForService(service);
StringmessageToDespatch=getMessage(message);
client.send(resolver,null,null,
messageToDespatch);
}
privateStringgetMessage(Stringmessage)
{
StringBufferstringBuffer=newStringBuffer();
stringBuffer.append("<hello>").append("
<helloRequest>").append("<message
xmlns=\"http://soap\">"+message+"</message>")
.append("</helloRequest>").append("</hello>");
returnstringBuffer.toString();
}
}
Perhaps,youmightgetstuckatthemessagebuildingsectionofthecodeabove.ThiswillleadtothefollowingXMLcode:
<hello>
<helloRequest>
<messagexmlns=\"http://soap\">"+message+"
</message>
</message>
</helloRequest>
</hello>
ThisisslightlydifferentfromtheusualSOAPenvelopedmessages,whichwesenttotheJBIbus.Thedifferenceisthatwedon'thaveaSOAPenvelope,butjustthemessage.ThisisbecausesimplebindingthePOJOusingservicemix-jsr181requirestheconsumertosendjustanormalized(XML)message,andnotaSOAPmessage.
Build,Deploy,andRuntheSampleThecodebaseforthissampleislocatedatch09\Jsr181PojoAccessBus.Tobuildtheentirecodebaseanddeploythesample,changedirectorytoch09\Jsr181PojoAccessBus,whichcontainsatop-levelbuild.xmlfile.Executeantasfollows:
cdch09\Jsr181PojoAccessBus
ant
Now,bringuptheServiceMixcontainerbyexecutingtheservicemix.xmlfilecontainedinthesamefolder,asshowninthefollowingcommands:
cdch09\Jsr181PojoAccessBus
%SERVICEMIX_HOME%/bin/servicemixservicemix.xml
TheClient.htmlfileprovidedagaininthesamefolder
canbeusedtosendmessagestotestthedeployedservice.
Forcompletenessofthesample,wealsohavecodetoaccesstheserviceusingtheAxisclientinthefolderch09\Jsr181PojoAccessBus\04_AxisClient.
TobuildtheentireAxisclientcodebase,assumingthatServiceMixisupandrunning,changedirectorytoch09\Jsr181PojoAccessBus\04_AxisClient,whichcontainsatop-levelbuild.xmlfile.Executeantasfollows:
cdch09\Jsr181PojoAccessBus
ant
ThiswillgeneratetherequiredAxisclient-sidestubsandcompiletheclientclasses.Nowtoruntheclient,executethefollowingcommand:
antrun
SummaryThischapterdiscussedPOJOclasses,andhowwecanhookthemontotheJBIbus.Hence,theservicesprovidedbytheseclassescanevenbeaccessedremotely,justlikeyouaccessanormalwebservice.JBIisallaboutSOIandthusprovidesaframeworkforintegratingcomponentsasservicestothebus.
Thisiswhatwehaveseeninthischapter,whenweboundaPOJOtotheNMRandaccesseditthroughnormalwebservicechannels.
Inthenextchapter,wewilllookintoyetanothercommonscenariofoundinproductionanddeploymentofwebservicesnamelyWebServicesGateways.
Chapter10.BindWebServicesinESB—WebServicesGatewaySinceSOIisallaboutintegratingmultipleSOA-basedsystems,webservicesplayacriticalroleintheintegrationspace.Thischapterisallabouttheimportanceofwebservicesinintegration.WewillusethesamplestoillustratehowtobindwebserviceswiththeServiceMixESBtofacilitateintegration.
Wewillcoverthefollowinginthischapter:
Webservicesandbinding
IntroductiontoHTTP
ServiceMix'sservicemix-httpcomponent
TheconsumerandproviderrolesfortheServiceMixJBIcomponents
servicemix-httpintheconsumerandproviderroles
Webservicebinding(Gateway)sample
WebServicesWebservicesseparateouttheservicecontractfromtheserviceinterface.ThisfeatureisoneofthemanycharacteristicrequiredforanSOA-basedarchitecture.Thus,eventhoughit
isnotmandatorythatweusethewebservicetoimplementanSOA-basedarchitecture,yetitisclearlyagreatenablerforSOA.
Webservicesarehardware,platform,andtechnologyneutralTheproducersand/orconsumerscanbeswappedwithoutnotifyingtheotherparty,yettheinformationcanflowseamlessly.AnESBcanplayavitalroletoprovidethisseparation.
BindingWebServicesAwebservice'scontractisspecifiedbyitsWSDLanditgivestheendpointdetailstoaccesstheservice.WhenwebindthewebserviceagaintoanESB,theresultwillbeadifferentendpoint,whichwecanadvertisetotheconsumer.Whenwedoso,itisverycriticalthatwedon'tloseanyinformationfromtheoriginalwebservicecontract.
WhyAnotherIndirection?Therecanbemultiplereasonsforwhywerequireanotherlevelofindirectionbetweentheconsumerandtheproviderofawebservice,bybindingatanESB.
Systemsexisttodaytosupportbusinessoperationsasdefinedbythebusinessprocesses.Ifasystemdoesn'tsupportabusinessprocessofanenterprise,thatsystemisoflittleuse.Businessprocessesareneverstatic.Iftheyremainstaticthenthereisnogrowthorinnovation,anditisdoomedtofail.
Hence,systemsorservicesshouldfacilitateagilebusinessprocesses.Thegoodarchitectureanddesignpracticeswillhelptobuild"servicestolast"butthatdoesn'tmeanourbusinessprocessesshouldbestable.Instead,businessprocesseswillevolvebyleveragingtheexistingservices.Thus,weneedaprocessworkbenchtoassembleandorchestrateserviceswithwhichwecan"MixandMatch"theservices.ESBisoneofthearchitecturaltopologieswherewecandothemixandmatchofservices.Todothis,wefirstbindtheexisting(andlonglasting)servicestotheESB.ThenleveragetheESBservices,suchasaggregationandtranslation,tomixandmatchthemandadvertisenewprocessesforbusinessestouse.
Moreover,therearecrossserviceconcernssuchasversioning,management,andmonitoring,whichweneedtotakecaretoimplementtheSOAathigherlevelsofmaturity.TheESBisagainonewaytodotheseaspectsofserviceorientation.
HTTPHTTPistheWorldWideWeb(www)protocolforinformationexchange.HTTPisbasedoncharacter-orientedstreamsandisfirewall-friendly.Hence,wecanalsoexchangeXMLstreams(whichareXMLencodedcharacterstreams)overHTTP.InawebserviceweexchangeXMLintheSOAP(SimpleObjectAccessProtocol)formatoverHTTP.Hence,theHTTPheadersexchangedwillbeslightlydifferentthananormalwebpageinteraction.Asamplewebservicerequestheaderisshownasfollows:
GETAxisEndToEndservices/HelloWebService?WSDL
HTTP/1.1
User-Agent:Java/1.6.0-rc
Host:localhost:8080
Accept:text/html,image/gif,image/jpeg,;q=.2,
/*;q=.2
Connection:keep-alive
POSTAxisEndToEndservices/HelloWebService
HTTP/1.0
Content-Type:text/xml;charset=utf-8
Accept:application/soap+xml,application/dime,
multipart/related,text/*
User-Agent:Axis/1.4
Host:localhost:8080
Cache-Control:no-cache
Pragma:no-cache
SOAPAction:""
Content-Length:507
Thefirstlinecontainsamethod,aURIandanHTTPversion,eachseparatedbyoneormoreblankspaces.Thesucceedinglinescontainmoreinformationregardingthewebserviceexchanged.
ESB-basedintegrationheavilyleveragestheHTTPprotocolduetoitsopennature,maturity,andacceptability.WewillnowlookatthesupportprovidedbytheServiceMixinusingHTTP.
ServiceMix'sservicemix-httpBindingexternalwebservicesattheESBlayercanbedoneinmultiplewaysbutthebestwayistoleverageJBIcomponents
suchastheservicemix-httpcomponentwithinServiceMix.WewilllookindetailathowtobindthewebservicesontotheJBIbus.
servicemix-httpinDetailservicemix-httpisusedforHTTPorSOAPbindingofservicesandcomponentsintotheServiceMixNMR.ForthisServiceMixusesanembeddedHTTPserverbasedontheJetty.
InChapter3,youhavealreadyseenthefollowingtwoServiceMixcomponents:
org.apache.servicemix.components.http.HttpInvoker
org.apache.servicemix.components.http.HttpConnector
Asoftoday,thesecomponentsaredeprecatedandthefunctionalityisreplacedbytheservicemix-httpstandardJBIcomponent.Afewofthefeaturesoftheservicemix-httpareasfollows:
SupportsSOAP1.1and1.2
SupportsMIMEwithattachments
SupportsSSL
SupportsWS-AddressingandWS-Security
SupportsWSDL-basedandXBean-baseddeployments
SupportforallMEPsasconsumersorproviders
Sinceservicemix-httpcanfunctionbothasaconsumer
andaprovider,itcaneffectivelyreplacethepreviousHttpInvokerandHttpConnectorcomponent.
ConsumerandProviderRolesWhenwespeakoftheConsumerandProviderrolesfortheServiceMixcomponents,thedifferenceisverysubtleatfirstsight,butveryimportantfromaprogrammerperspective.ThefollowingfigureshowstheConsumerandProviderrolesintheServiceMixESB:
Theabovefigureshowstwoinstancesofservicemix-httpdeployedintheServiceMixESB,oneinaproviderrole
andtheotherintheconsumerrole.Asitisevident,theserolesarewithrespecttotheNMRoftheESB.Inotherwords,aconsumerroleimpliesthatthecomponentisaconsumertotheNMRwhereasaproviderroleimpliestheNMRistheconsumertothecomponent.Basedontheseroles,theNMRwilltakeresponsibilityofanyformatorprotocolconversionsfortheinteractingcomponents.
Letusalsointroducetwomorepartiesheretomaketheroleofaconsumerandaproviderclear—aclientandaservice.Inatraditionalprogrammingparadigm,theclientinteractsdirectlywiththeserver(orservice)toavailthefunctionality.IntheESBmodel,boththeclientandtheserviceinteractwitheachotheronlythroughtheESB.Hence,theclientandtheserviceneedpeerswiththeirrespectiverolesassigned,whichinturnwillinteractwitheachother.Thus,theESBconsumerandproviderrolescanberegardedasthepeerrolesfortheclientandtheservicerespectively.
AnyclientrequestwillbedelegatedtotheconsumerpeerwhointurninteractswiththeNMR.ThisisbecausetheclientisunawareoftheESBandtheNMRprotocolorformat.However,theservicemix-httpconsumerknowshowtointeractwiththeNMR.Henceanyrequestfromtheclientwillbetranslatedbytheservicemix-httpconsumeranddeliveredtotheNMR.Ontheservicesidealso,theNMRneedstoinvoketheservice.Buttheserverserviceisneutralofanyspecificvendor'sNMRanddoesn'tunderstandtheNMRlanguageassuch.Apeerproviderrolewillhelphere.TheproviderreceivestherequestfromtheNMR,translatesitintotheactualformatorprotocoloftheserverserviceandinvokes
theservice.Anyresponsewillalsofollowthereversesequence.
servicemix-httpXBeanConfigurationTheservicemix-httpcomponentssupportstheXBean-baseddeployment.Sincetheservicemix-httpcomponentcanbeconfiguredinboththeconsumerandproviderroles,wehavetwosetsofconfigurationparametersforthecomponent.Letuslookintothemainconfigurationparameters:
servicemix-httpasconsumer:Asampleservicemix-httpconsumercomponentconfigurationisshownasfollows:
<http:endpoint
service="test:MyConsumerService"
endpoint="HelloWebService"role="consumer"
targetService="test:IHelloWebService"
locationURI="http://localhost:8081/services/
HelloWebService"soap="true"
defaultMep="http://www.w3.org/2004/08/wsdl/in-out"
wsdlResource="http://localhost:8080AxisEndToEnd
services/HelloWebService?WSDL"/>
Thefollowingtablegivestheexplanationforthemainconfigurationparameters:
AttributeNa
Type Description
MandatoryorNot
me
service
QName
Servicenameoftheproxyendpoint Mandatory
endpoint
String
Endpointnameoftheproxyendpoint
Mandatory
interfaceName
QName
Interfacenameoftheproxyendpoint
NotMandatory
targetService
QName
Servicenameofthetargetendpoint NotMandatory.Defaultisthevalueoftheserviceattribute
targetEndpoint
String
Endpointnameofthetargetendpoint
NotMandatory.Defaultisthevalueoftheendpointattribute
role Stri Whetheraconsumeroraprovider Mandatory.Value
role String
Whetheraconsumeroraprovider Mandatory.Valueshouldbeconsumer
locationURI
URI
HttpURLwherethisproxyendpointwillbeexposedsothattheESBclientscanaccesstheproxyservice.
Mandatory
defaultMEP
URI
TheMEPURIbywhichclientsinteractwiththeconsumercomponent
NotMandatory
soap
boolean
Ifitistrue,thecomponentwillparsetheSOAPenvelopeandpassthecontentstotheNMR
NotMandatory.Defaultvalueisfalse.
wsdlResource
SpringResource
Ifitisset,theWSDLwillberetrievedfromthisconfiguredSpringresource.
NotMandatory
Thus,thelocationURIattributeintheservicemix-httpconsumerreferstotheHttpURLwherethisproxyendpointisexposed,sothattheESBclientscanaccesstheproxyservice.LaterwewilllookathowtogeneratestaticclientstubsoutofthisproxyURI.
servicemix-httpasprovider:Whileconfiguringtheprovider,thereareafewaspectstobetakencareofwithrespecttotheWSDL.IfwehavethesampleWSDLasshownasfollows:
<?xmlversion="1.0"encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="http://AxisEndToEnd.axis.
apache.binildas.com"
xmlns:impl="http://AxisEndToEnd.axis.apache.
binildas.com"><!--otherdescriptions-->
<wsdl:servicename="IHelloWebService">
<wsdl:port
binding="impl:HelloWebServiceSoapBinding"
name="HelloWebService">
<wsdlsoap:address
location="http://localhost:8080/
AxisEndToEnd/services/HelloWebService">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
Now,whileconfiguringtheprovidercomponentyouneedtoensurethattheservice(IHelloWebService)andtheendpoint(HelloWebService)matchtheservicenameandportelementsoftheWSDLthatyouusetocorrectlyreturntheWSDLfortheendpoint.Moreover,theservicenamewillusethetargetNamespacefortheWSDL(http://AxisEndToEnd.axis.apache.binildas.com).
Asampleservicemix-httpprovidercomponentconfigurationisshownasfollows:
<http:endpointservice="test:IHelloWebService"
endpoint="HelloWebService"role="provider"
Thefollowingtablethegivestheexplanationforthemainconfigurationparameters:
AttributeName
Type Description MandatoryorNot
service
QName
Servicenameoftheexposedendpoint Mandatory
endpoint
String Endpointnameoftheexposedendpoint Mandatory
interfaceName
QName
Interfacenameoftheexposedendpoint NotMandatory
locationURI="http://localhost:8080AxisEndToEnd
services/HelloWebService"
soap="true"
soapAction=""
wsdlResource="http://localhost:8080AxisEndToEnd
services/HelloWebService?WSDL"/>
role String Whetheraconsumeroraprovider Mandatory.Valueshouldbeprovider
locationURI
URI HttpURLofthetargetservice. Mandatory
soap boolean
Ifitistrue,thecomponentwillparsetheSOAPenvelopeandpassthecontentstotheNMR
NotMandatory.Defaultvalueisfalse.
soapAction
String TheSOAPActionheadertobesendoverHTTPwheninvokingthewebservice
NotMandatory.Defaultvalueis"".
wsdlResource
SpringResource
Ifitisset,theWSDLwillberetrievedfromthisconfiguredSpringresource.
NotMandatory
servicemix-httpLightweightConfigurationInadditiontotheXBean-basedconfiguration,servicemix-httpcanalsobedeployedbasedonthelightweightmodetouseinanembeddedServiceMix.Theconfigurationwouldbeasfollows:
<sm:activationSpec>
<sm:component>
<http:component>
<http:endpoints>
<http:endpointservice="test:IHelloWebService"
endpoint="HelloWebService"role="provider"
locationURI="http://localhost:8080/
AxisEndToEnd/services/HelloWebService"soap="true"soapAction=""
wsdlResource="http://localhost:8080/AxisEndToEnd/services/
HelloWebService?WSDL">
<http:endpointservice="test:MyConsumerService"
endpoint="HelloWebService"role="consumer"
targetService="test:IHelloWebService"
locationURI="http:/localhost:8081/services/HelloWebService"
soap="true"
defaultMep="http://www.w3.org/2004/08/wsdl/in-out"
wsdlResource="http://localhost:8080/AxisEndToEnd/services/
HelloWebService?WSDL">
<http:endpoints>
</http:component>
</sm:component>
</sm:activationSpec>
WebServiceBindingSampleWewillnowlookatacompletesampleofhowtobindawebservicetotheServiceMix.Whiledoingso,wewillalsoseehowtousetheApacheAxisclient-sidetoolstogeneratestubsbasedonthebindingatServiceMix.NormallywepointtotheactualWSDLURLtogenerateclientstubs,butinthisexamplewewillpointthetoolstotheServiceMixbinding.ThentheServiceMixbindingwillactcompletelyasthewebservicegatewayvisibletotheexternalclients,thusshieldingtheactualwebserviceinthebackground.
SampleUseCaseByusingawebservicesgateway,youcanusetheintermediationtobuildanddeploythewebservicesroutingapplication.Butkeepinmindthattheroutingisjustoneofthevarioustechnicalfunctionalitiesthatyoucanimplementatthegateway.Foroursampleusecase,wehaveanexternalwebservice,deployedandhostedinanoderemotetotheESB.IntheESB,wewillsetupaWebServicesGateway,whichcanproxytheremotewebservice.Theentiresetupisshowninthefollowingfigure:
Alongwiththepreviousdiscussion,weneedtheservicemix-httpintheconsumerandproviderroles.MyConsumerServiceisaservicemix-httpcomponentintheconsumerroleandIHelloWebServiceisaservicemix-httpcomponentintheproviderrole.Bothofthemareshowninthefollowing
figure:
LetusnowtakeacloserlookatthegatewayconfiguredintheESB.Here,weconfigureservicemix-httpinboththeconsumerandproviderrolesandhookittotheNMR.AnyclientrequestsareinterceptedbytheconsumerandtheconsumerthensendstherequestonbehalfoftheclienttotheNMR.Fromtheretherequestwillberoutedtothedestinationwebservicethroughtheprovider.Themessageflowismarkedinsequenceinthefollowingfigure:
DeploytheWebServiceAsafirststep,ifyouhaven'tdoneitbefore,editexamples.PROPERTIES(providedalongwiththecodedownloadforthischapter),andchangethepathstheretomatchyourdevelopmentenvironment.ThecodedownloadforthischapteralsoincludesaREADME.txtfile,whichgivesdetailedstepstobuildandrunthesamples.
Wehaveasimplewebserviceinthecodebasepresentinthefolderch10\ServiceMixHttpBinding\01_ws.Todeploythewebservice,firstchangedirectorytothech10\ServiceMixHttpBindingfolderandexecutetheantcommandasfollows:
cdch10\ServiceMixHttpBinding
ant
Infact,thebuild.xmlfilewillcallthebuildinthesubprojectstobuildthewebserviceaswellastheServiceMixsubproject.
Thewebserviceisbuiltcompletelyandthewarfilecanbefoundinthefolderch10\ServiceMixHttpBinding\01_ws\dist\AxisEndToEnd.war
.Todeploythewebservice,dropthiswarfileintoyourfavoritewebserver'swebappsfolderandrestartthewebserver,ifnecessary.
Nowtomakesurethatyourwebservicedeploymentworksfine,wehaveprovidedawebservicetestclient.Toinvokethetestclient,executethefollowingcommands:
cdch10\ServiceMixHttpBinding\01_ws
antrun
WecanalsocheckthewebservicedeploymentbyaccessingtheWSDLfromtheURL:http://localhost:8080AxisEndToEndservices/HelloWebServ
ice?WSDL
LetuslistouttheWSDLhere,sincewewanttocompareitwiththeWSDLaccessedfromtheServiceMixbindinglatertocrosscheckthesimilarities.Thisisprovidedinch10\ServiceMixHttpBinding\HelloWebService-axis.wsdl
<?xmlversion="1.0"encoding="UTF-8"?>
<wsdl:definitionstargetNamespace="http://AxisEndToEnd.axis.
apache.binildas.com"
xmlns:apachesoap="http://xml.apache.org/xmlsoap"
xmlns:impl="http://AxisEndToEnd.axis.apache.binildas.com"
xmlns:intf="http://AxisEndToEnd.axis.apache.binildas.com"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<schemaelementFormDefault="qualified"
targetNamespace="http://AxisEndToEnd.axis.apache.binildas.com"
xmlns="http://www.w3.org/2001/XMLSchema">
<elementname="hello">
<complexType>
<sequence>
<elementname="in0"type="xsd:string">
<sequence>
</complexType>
</element>
<elementname="helloResponse">
<complexType>
<sequence>
<elementname="helloReturn"type="xsd:string">
<sequence>
</complexType>
</element>
</schema>
</wsdl:types>
<wsdl:messagename="helloRequest">
<wsdl:partelement="impl:hello"name="parameters">
<wsdl:message>
<wsdl:messagename="helloResponse">
<wsdl:partelement="impl:helloResponse"name="parameters">
<wsdl:message>
<wsdl:portTypename="IHelloWeb">
<wsdl:operationname="hello">
<wsdl:inputmessage="impl:helloRequest"name="helloRequest"/>
<wsdl:outputmessage="impl:helloResponse"name="helloResponse">
<wsdl:operation>
</wsdl:portType>
<wsdl:bindingname="HelloWebServiceSoapBinding"
type="impl:IHelloWeb">
<wsdlsoap:bindingstyle="document"transport="http://schemas.
xmlsoap.org/soap/http">
<wsdl:operationname="hello">
<wsdlsoap:operationsoapAction="">
<wsdl:inputname="helloRequest">
<wsdlsoap:bodyuse="literal">
<wsdl:input>
<wsdl:outputname="helloResponse">
<wsdlsoap:bodyuse="literal">
<wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:servicename="IHelloWebService">
<wsdl:portbinding="impl:HelloWebServiceSoapBinding"
name="HelloWebService">
<wsdlsoap:addresslocation="http://localhost:8080/
AxisEndToEnd/services/HelloWebService">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
XBean-basedservicemix-httpBinding
ForXBean-baseddeploymentofservicemix-http,ourxbean.xmlmatchesthefollowing:
<beansxmlns:http="http://servicemix.apache.org/http/1.0"
xmlns:test="http://AxisEndToEnd.axis.apache.binildas.com">
<classpath>
<location>.</location>
</classpath>
<http:endpointservice="test:IHelloWebService"
endpoint="HelloWebService"role="provider"
locationURI="http://localhost:8080AxisEndToEnd
services/HelloWebService"soap="true"soapAction=""
wsdlResource="http://localhost:8080AxisEndToEnd
services/HelloWebService?WSDL">
<http:endpointservice="test:MyConsumerService"
endpoint="HelloWebService"role="consumer"
targetService="test:IHelloWebService"
locationURI="http:/localhost:8081/services/HelloWebService"
soap="true"defaultMep="http://www.w3.org/2004/08/wsdl/in-out"
wsdlResource="http://localhost:8080AxisEndToEnd
services/HelloWebService?WSDL">
<beans>
Thepreviousexecutionofanthasalreadybuiltandpackagedtheserviceassemblyforthesample.
DeployingandRunningtheSampleTodeploytheServiceMixsample,wehavethefollowingservicemix.xml:
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:binil="http://www.binildas.com/voipservice">
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"value="classpath:servicemix.properties"
>
<bean>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<sm:containerid="jbi"MBeanServer="#jmxServer"
useMBeanServer="true"createMBeanServer="true"rootDir="./wdir"
installationDirPath="./install"deploymentDirPath="./deploy"
flowName="seda">
<sm:activationSpecs>
</sm:activationSpecs>
</sm:container>
</beans>
TobringuptheServiceMix,changedirectorytoch10\ServiceMixHttpBindingandexecutetheServiceMixscriptasfollows.
cdch10\ServiceMixHttpBinding
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
WecannowtestourServiceMixdeploymentbyusingthefollowingtestclient:
ch10\ServiceMixHttpBinding\Client.html
AccessWSDLandGenerateAxisStubstoAccesstheWebServiceRemotely
Nowforthereallycoolstuff.Aswediscussedearlier,wehavesetuptheServiceMixasaseparatewebservicegatewayinfrontoftheactualwebservicedeployment.NowwehavetocheckwhetherwecanaccesstheWSDLfromtheServiceMix.Forthis,wecanpointourbrowserusingthestandardWSDLquerystring,like:
http://localhost:8081/services/HelloWebService/?wsdl
or
http://localhost:8081/services/HelloWebService/main.ws
dl
Notethat,theaboveURLpointstothelocationURIattributeconfiguredfortheconsumercomponent,whichishttp://localhost:8081/services/HelloWebService.TheWSDLplacedinlocationch10\ServiceMixHttpBinding\HelloWebService-esb.wsdl,matchesthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:apachesoap="http://xml.apache.org/xmlsoap"
xmlns:impl="http://AxisEndToEnd.axis.apache.binildas.com"
xmlns:intf="http://AxisEndToEnd.axis.apache.binildas.com"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://AxisEndToEnd.axis.apache.binildas.com">
<wsdl:types>
<schemaxmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://AxisEndToEnd.axis.apache.binildas.com">
<elementname="hello">
<complexType>
<sequence>
<elementname="in0"type="xsd:string">
<sequence>
</complexType>
</element>
<elementname="helloResponse">
<complexType>
<sequence>
<elementname="helloReturn"type="xsd:string">
<sequence>
</complexType>
</element>
</schema>
</wsdl:types>
<wsdl:messagename="helloRequest">
<wsdl:partelement="impl:hello"name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:messagename="helloResponse">
<wsdl:partelement="impl:helloResponse"name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:portTypename="IHelloWeb">
<wsdl:operationname="hello">
<wsdl:inputmessage="impl:helloRequest"name="helloRequest">
</wsdl:input>
<wsdl:outputmessage="impl:helloResponse"name="helloResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:bindingname="HelloWebServiceBinding"
type="impl:IHelloWeb">
<wsdlsoap:bindingstyle="document"
transport="http://schemas.xmlsoap.org/soap/http">
<wsdl:operationname="hello">
<wsdlsoap:operationsoapAction="">
<wsdl:inputname="helloRequest">
<wsdlsoap:bodyuse="literal">
<wsdl:input>
<wsdl:outputname="helloResponse">
<wsdlsoap:bodyuse="literal">
<wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:servicename="MyConsumerService">
<wsdl:portbinding="impl:HelloWebServiceBinding"
name="HelloWebService">
<wsdlsoap:addresslocation="http://localhost:8081/
services/HelloWebService/">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
IfwecomparethetwoWSDL,themajordifferenceisintheservicedescriptionsection.Here,ServiceMixformstheserviceandportnametakingvaluesfromserviceandendpointattributesoftheconsumerservice—MyConsumerServiceandHelloWebServicerespectively.
IfweareabletoretrievetheWSDL,thenextstepistousetheApacheAxistoolstoauto-generatetheclient-sidestubsandbindingclasses,usingwhichwecanwritesimpleJavaclientcodetoaccesstheservicethroughHTTPchannel.TheAxisclientclassesareplacedinthedirectorych10\ServiceMixHttpBinding\03_AxisClient.
Todothat,wehavetousethewsdl2javaanttask.Letusfirstdeclarethetaskdefinitionandexecutethattasktogeneratethestubclasses.
<taskdefname="wsdl2java"
classname="org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask"
loaderref="axis">
<classpathrefid="classpath">
<taskdef>
<targetname="wsdl2java">
<javaclassname="org.apache.axis.wsdl.WSDL2Java"fork="true"
failonerror="true">
<argvalue="-o">
<argvalue="${src}">
<argvalue="-x">
<argvalue="http:/io.java">
<argvalue="http:/localhost:8081/services/HelloWebService/
main.wsdl">
<classpath>
<pathrefid="classpath">
<pathelementlocation="${build}">
<classpath>
</java>
</target>
ThetaskwillextracttheWSDLfromthespecifiedlocationandgeneratethefollowingclient-sideartifacts:
com\binildas\apache\axis\AxisEndToEnd\HelloWebServiceBindingStub.java
webservicebindingsampleAxis-basedstubs,
generatingcom\binildas\apache\axis\AxisEndToEnd\IHelloWeb.java
com\binildas\apache\axis\AxisEndToEnd\MyConsumerService.java
com\binildas\apache\axis\AxisEndToEnd\MyConsumerServiceLocator.java
TheClientJavaclasscanbewrittenagainstthesegeneratedfilesasfollows:
publicclassClient
{
privatestaticStringwsdlUrl="http://localhost:8081/services/
HelloWebService/main.wsdl";
privatestaticStringnamespaceURI="http://AxisEndToEnd.
axis.apache.binildas.com";
privatestaticStringlocalPart="MyConsumerService";
protectedvoidexecuteClient(String[]args)throwsException
{
{
MyConsumerServicemyConsumerService=null;
IHelloWebiHelloWeb=null;
if(args.length==3)
{
myConsumerService=newMyConsumerServiceLocator(args[0],new
QName(args[1],args[2]));
}
else
{
myConsumerService=newMyConsumerServiceLocator(wsdlUrl,new
QName(namespaceURI,localPart));
}
iHelloWeb=myConsumerService.getHelloWebService();
}
publicstaticvoidmain(String[]args)throwsException
{
Clientclient=newClient();
client.executeClient(args);
}
}
TobuildtheentireAxisclientcodebase,assumingthattheServiceMixisupandrunning,changedirectorytoch10\ServiceMixHttpBinding\03_AxisClient,whichcontainsabuild.xmlfile.Executeantasshownasfollows:
cdch10\ServiceMixHttpBinding\03_AxisClient
ant
ThiswillgeneratetherequiredAxisclient-sidestubsandcompiletheclientclasses.Nowtoruntheclient,executethefollowingcommand:
antrun
SummaryWestartedthischapterbyintroducingtheservicemix-httpJBIcomponent.ThenwelookedatthesamplesofbindingwebservicestoESBusingtheservicemix-httpbindingcomponent.Bydoingso,wehave,infact,implementedacompletefunctionalwebservicesgatewayattheESB.
Alotoftimes,weutilizethispatterntoexposeusefulwebserviceshosteddeepinsideyourcorporatenetworksprotectedbymultiplelevelsoffirewall.Whenwedoso,thewebservicesgatewayistheaccesspointforanyexternalclient.Itshouldmocktheactualwebservicenotonlyinprovidingthefunctionalitybutalsoinexposingthewebservicescontract(WSDL).Now,doyouwanttoimprovetheQOSattributesofyourwebservice?
ThenextchapterwilltakeyouthroughasimilarexercisebydemonstratinghowtoaccessyourHTTP-basedwebservicesthroughanMOMchannellikeJMS.
Chapter11.AccessWebServicesUsingtheJMSChannelWebservicesaregreatenablersfortheSOAarchitectureswhichareneutraloftheunderlyingplatformandtechnology.Itcanalsopenetratethroughthecorporatefirewalls,thusactingasaremotecontrolswitch.However,attimes,wemaywanttoguaranteeafewQOSaspectsofthisserviceinvocation.ThereliabilityoftheHTTPtransportchannelmaynotbesufficientforscenariossuchasthis.Inthischapter,wewilllookathowJavaJMS,whichisaplatform-dependentmessagingtechnology,canincreasetheQOSfeaturesofthewebservices.
Sowewilllookatthefollowinginthischapter:
WhatisJMS?
Reliabilityandwebservices.
SOAPversusJMS.
JMSsupportingcomponentsinServiceMix.
AprotocolbridgetoconvertHTTPtoJMS.
AsampledemonstratingthebindingofwebservicestoaJMSchannel.
JMSJMSdefinesthestandardforareliableenterprisemessaging,alsoreferredtoasMOM.Enterprisemessagingprovidesareliableandflexiblemechanismforthelooselycoupled(asynchronous)exchangeofcriticalbusinessdataandeventsthroughoutanenterprise.TheJMSAPIaddstothisacommonAPIandaproviderframeworkthatenablesthedevelopmentofportable,message-basedapplicationsintheJavaprogramminglanguage.
TheJMSAPIenhancesJ2EEinthefollowingways:
Message-drivenbeansbasedontheJMSenabletheasynchronousconsumptionoftheJMSmessages.
JMSmessageexchangecanparticipateintheJavaTransactionAPI(JTA)transactions.
TheJCAinterfacesallowJMSimplementationsfromdifferentvendorstobeexternallypluggedintoaJ2EEenvironment.
SinceMOMdefinesthebackboneformanyESBimplementations,JMSplaysacriticalroleinJava-basedESB.
WebServiceandJMSReliabilityisoftheprimeconcernincriticalapplications,especiallyininteractionsinvolvingfinancialtransactions.Considerthescenariooffundtransferwherewedebitoneaccountandcreditanotheraccountwiththesameamountofmoney.Wecannotalloweitherofthesetransactionstofailor
todebittwiceinanaccountasaresultofmessageduplications.UnreliabletransportchannelslikeHTTPandnon-reliabilityinmessagedeliverywillimpedethecorrectnessofthemissioncriticaltransactions.ThisiswherethealternativestoSOAPoverHTTP,whichisbeingexplored.
SpecificationsforWebServiceReliableMessagingThewebservicesworlddefinestwospecificationstointroducereliability,namely:
WS-Reliability.
WS-ReliableMessaging.
BoththesespecificationsuseSOAPheaderstoexchangemessagegroupingandcorrelationinformationbetweenaconsumerandaprovidersothatthereliabilitylayercanguaranteethefollowingqualityconcerns:
Guaranteeddelivery.
Onceandonlyoncedelivery.
Messageordering.
WebServicesReliability(WS-Reliability)isaSOAP-basedprotocolwiththepurposeofexchangingSOAPmessageswithguaranteeddelivery,noduplicates,andguaranteedmessageordering.WS-ReliabilityisdefinedasSOAPheaderextensionsandis,infact,independentoftheunderlyingprotocolused.Atthesametime,thisspecificationcontainsa
bindingtoHTTP.ThereliablemessageprotocolisabstractedfromthecommunicationbetweenasendingReliableMessagingProcessor(RMP)andareceivingRMP.HencetheSOAPintermediariesdonotplayanyactiveroleinthereliabilitymechanisms.WS-ReliabilitywaspublishedinJanuary2003byHitachi,Oracle,Sonic,andSunMicrosystems,andthensubmittedtotheOASISWebServicesReliableMessagingTechnicalCommittee.
TheWebServicesReliableMessaging(WSRM)protocolisbasedontheWS-ReliablemessagingspecificationandwaspublishedinMarch2003bysoftwaremajorsincludingBEA,IBM,Microsoft,andTibco.WSRMalsoworkssimilartowebservicesreliability.Insteadofagroup,theWSRMhasthenotionofasequencetoensuremessagereliabilityconcerns.
Dependinguponthecriticalityofthebusinessapplications,varyingordersofreliabilitymightberequiredandWSRM-basedproductswillsupportthis.However,boththeWSRMspecificationsaresilentonmanyoftheaspects.Afewofthesearelistedasfollows:
Undeliverablemessages—Nodefinitionofdeadletterqueue.
Messagepriority.
Messagepersistence.
TheaboveaspectsareoutofthescopeoftheWSRMspecifications,eventhoughtheimplementationsofreliablemessagingneedstoaddressalloranyofthemdependingupontheorderofreliabilityrequired.TraditionalJMS-basedMOMprovideswaystoaddresstheaboveconcerns,whichwecan
leverageeveninnormalwebservices.ItisinthiscontextthatweneedtolookintocombiningtheMOMinfrastructurewithSOAP(WebServices),togetthebestofboththeworlds.
SOAPoverHTTPversusSOAPoverJMSSOAPistransportindependentandcanbeboundtoanytransport.TheusualtransportbindingforSOAPisHTTPandSOAPoverHTTPiswhatweusuallylookatasinteroperable.HTTPbelongstotheapplicationlayerofboththeOpenSystemInterface(OSI)model(layer7)andtheInternetProtocol(IP)suite(layer4or5).
ThefollowingWSDLsnippetshowswhatforaHTTPboundSOAPmessagelookslike:
<wsdl:definitions>
<wsdl:bindingname="HelloWebServiceSoapBinding"
type="impl:IHelloWeb">
<wsdlsoap:bindingstyle="document"
transport="http://schemas.xmlsoap.orgsoaphttp">
<wsdl:binding>
<wsdl:servicename="IHelloWebService">
<wsdl:port
binding="impl:HelloWebServiceSoapBinding"
name="HelloWebService">
<wsdlsoap:address
location="http://localhost:8080/
AxisEndToEnd/services/HelloWebService">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
DuetothemanyQOSfeaturesofJMS,SOAPoverJMSoffersmorereliableandscalablemessagingsupportthanSOAPoverHTTP.BybuildingontopoftheJMS,SOAPoverJMSsupportstwomessagingstyles—one-wayrequeststyleandtwo-wayrequestandresponsestyle.One-wayrequestmessagingallowsawebserviceclienttounblockitselfwhentherequestmessagereachesaJMSqueueortopic.Two-wayrequestandresponsemessagingblocksawebserviceclientuntiltherequestreachestheserverandaresponsemessageisreceivedbackattheclient-side.AsampleWSDLsnippetisshownisshownasfollows:
<wsdl:definitions>
<wsdl:bindingname="HelloWebServiceSoapBinding"
type="impl:IHelloWeb">
<wsdlsoap:bindingstyle="document"
transport="http://schemas.xmlsoap.org/soap/jms">
<wsdl:binding>
<wsdl:servicename="IHelloWebService">
<wsdl:port
binding="impl:HelloWebServiceSoapBinding"
name="HelloWebService">
<wsdlsoap:addresslocation="jms:/queue?
destination==jms/queue&
connectionFactory=weblogic.jndi.
WLInitialContextFactory">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
ButthedownsideisthatSOAPoverJMSisnotyetstandardizedandhencemaynotbeinteroperableacrossplatforms.ThisisbecauseJMSisnotan"over-the-wire"protocol.Instead,JMSisaJavaAPIwhichrequiresaclientto
JMSinServiceMixServiceMixprovidesuswiththeservicemix-jmscomponentwhichmakesiteasytobindtheendpointstotheJMSchannel,bothintheconsumerandproviderroles.Hence,beforewelookintothedetailsonhowtobindthewebservicestotheJMStransport,wewilllookatconfiguringtheservicemix-jmscomponent.
useaJMSproviderlibrary(ajarfile)providedbythevendoroftheJMSserviceprovider.ThisisanalogoustorequiringaJDBCdriversimilartoclasses12.jarfromOracleforconnectingtoanOracleserverfromajavaapplication.Theactual"over-the-wire"protocoltobeusedunderthecoverswithintheJMSproviderlibraryisnotdefinedandisleftopenforvendorstohavetheirownimplementations.Theinteroperabilityisnoteasyevenifweconsiderthejavaworldalone.Thatis,ifwehaveanIBMWebsphereJMSproviderandaclientprogramfromwithintheBEAWeblogicapplicationserverneedtoaccesstheJMSserver.Eventhoughboththeplatformsarejava-based,theintegrationmightnotbestraightforwardduetotheJMSimplementationclashes.Moreover,JMSbeinganAPIdoesn'taskvendorstoimplementanyadditionalservicesanddoesn'tstandardizethedatastructureexchanged.However,JMSstillisaviablemechanismtoMOMthatenableswebservices.
Servicemix-jmsTheservicemix-jmscomponentsallowyoutosendandreceiveJMSmessages.Theservicemix-jmscomponentsassumethatthenormalizedmessagetheyaregivenisreadyformarshallingintooroutofJMS.Hence,theydon't,bydefault,trytoimplementaSOAPstackorperformanycomplexmessagetransformationotherthantomapnormalizedmessagestoJMSorviceversa.However,itispossibletospecifytheSOAPenvelopedpayloadasmessagessothatservicemix-jmscanperformwrappingandunwrappingofpayloadfromwithintheSOAPenvelope.
Afewofthefeaturesofservicemix-jmsareasfollows:
StandardJBI-compliantbindingcomponent.
SupportslightweightandXBean-baseddeployments.
SupportsSOAP1.1and1.2support.
SupportsMIMEwithattachments.
SupportsWS-Addressing.
SupportforallMEPsintheconsumerortheproviderrole.
ConsumerandProviderRolesservicemix-jmscanbeconfiguredbothasaconsumerandaproviderofservices.Similartoservicemix-http,theserolesarewithrespecttotheNMRoftheESB.Inotherwords,aconsumerroleimpliesthatthecomponentisaconsumertotheNMRwhereasaproviderroleimpliesthattheNMRistheconsumertothecomponent.Basedontheseroles,theNMRwilltakeresponsibilityofanyformatorprotocolconversionsfortheinteractingcomponents.YoucanrefertotheConsumerandProviderRolessectioninChapter10tounderstandmoreonthecontractandresponsibilityoftheseroles.
servicemix-jmsXBeanConfigurationTheservicemix-jmscomponentsupportstheXBean-baseddeployment.Sincetheservicemix-jmscomponentcanbeconfiguredinboththeconsumerandproviderroles,wehavetwosetsofconfigurationparametersforthecomponent.Letuslookintothemainconfigurationparameterslistedasfollows:
servicemix-jmsasconsumer:Asampleservicemix-jmsconsumercomponentconfigurationisshownasfollows:
<jms:endpointservice="test:MyConsumerService"
endpoint="myConsumer"role="consumer"soap="true"
targetService="test:pipeline"
defaultMep="http://www.w3.org/2004/08/wsdl/in-only"
destinationStyle="queue"jmsProviderDestinationName="queue/A"
connectionFactory="#connectionFactory"/>
Thefollowingtablelistsoutthemainattributesusedtoconfigureservicemix-jmscomponentintheconsumerrole:
AttributeName
Type Description MandatoryorNot
service
QName
Servicenameofproxyendpoint. Mandatory.
endpoi
String Endpointnameofproxyendpoint. Mandatory.
point
role String Whetheraconsumeroraprovider. Mandatory.Valueshouldbeconsumer.
soap
boolean
Ifitistrue,thecomponentwillparsetheSOAPenvelopeandpassthecontentstotheNMR.
NotMandatory.Defaultvalueisfalse.
targetService
QName
Servicenameofthetargetendpoint. NotMandatory.Defaultisthevalueoftheserviceattribute.
defaultMEP
URI TheMEPURIbywhichclientsinteractwiththeconsumercomponent.
NotMandatory.
destinationStyle
String IndicatesthedestinationtypeusedwiththejmsProviderDestinationName.
NotMandatory(unlessjmsProviderDestinationNameisused).
jmsPro
String ThetargetJMSdestination(QueueorTopic)willbecreatedbytheJMSprovider.
NotMandatory(eitherofdestination,
Provider
DestinationNa
me
willbecreatedbytheJMSprovider. destination,jndiDestinationNameorjmsProviderDestinationNameismandatory).
connectionFactory
javax.jms.ConnectionFactory
TheconnectionFactoryistobeused.InsteadaJNDIconfigurationcanbeprovidedusingjndiConnectionFactoryName.
NotMandatory.
useMsgIdInResponse
boolean
TruevalueindicatesthattheJMScorrelationidwillbesettotheidoftheJMSrequestmessage—ifitisfalse,anartificialcorrelationidwillbeusedinstead.
NotMandatory(inwhichcasethedefaultbehaviouristousethemessageexchangeidasthecorrelationid).
Inthesampleconfigurationlistedearlier,ifaclienthastosendamessagetotheNMRithastoplacethemessageinthequeuequeue/A.SincetheMEPisin-only,theclientwillnotreceiveanyresponse.Hence,ifaclienthastosendanormalrequest-responsetotheNMR,thenweneedtouseadditionalMEPconversionbridges(Note:thetargetServiceinthesampleconfigurationwhichisanMEPconversionpipeline,whichwillbedemonstratedinanexampleinthischapter).Eventhatisnotsufficientsinceweneedamechanismtoco-relaterequestandresponsemessages.ThiscanbedonebysettingtheJMScorrelationid(eventhoughwedon'tdemonstratethisinoursample).
servicemix-jmsasprovider:Asampleservicemix-jmsprovidercomponentconfigurationisshownasfollows:
<jms:endpointservice="test:MyProviderService"
endpoint="myProvider"role="provider"soap="true"
destinationStyle="queue"jmsProviderDestinationName="queue/B"
connectionFactory="#connectionFactory"/>
Thefollowingtablelistsoutthemainattributesusedtoconfiguretheservicemix-jmscomponentintheproviderrole:
AttributeName
Type Description MandatoryorNot
service QName Servicenameoftheexposedendpoint. Mandatory.
endpoint
String Endpointnameoftheexposedendpoint. Mandatory.
role String Whetheraconsumeroraprovider. Mandatory.Valueshouldbeprovider.
soap boolean Ifitistrue,thecomponentwillparsetheSOAPenvelopeandpassthecontentstotheNMR.
NotMandatory.Defaultvalueisfalse.
destinati String Indicatesthedestinationtypeusedwith NotMandatory(unlessjmsProvider
onStyle thejmsProviderDestinationName. DestinationNameisused).
jmsProv
iderDestinationName
String ThetargetJMSdestination(Queueor
Topic)willbecreatedbytheJMSprovider.
NotMandatory(eitherof
destination,jndiDestinationName,orjmsProviderDestinationNameismandatory).
connectionFactory
javax.jms.ConnectionFactory
TheconnectionFactoryistobeused.InsteadaJNDIconfigurationcanbeprovidedusingjndiConnectionFactoryName.
NotMandatory.
servicemix-jmsLightweightConfigurationInadditiontotheXBean-basedconfigurationlistedearlier,servicemix-jmscanalsobedeployedbasedonthelightweightmodeforuseinanembeddedServiceMix.Theconfigurationwouldbeasfollows:
<sm:activationSpec>
<sm:component>
<jms:component>
<jms:endpoints>
<jms:endpointservice="test:MyConsumerService"
endpoint="myConsumer"role="consumer"
soap="true"targetService="test:pipeline"
defaultMep="http://www.w3.org/2004/08/wsdl/in-only"
destinationStyle="queue"
jmsProviderDestinationName="queue/A"connectionFactory
="#connectionFactory">
<jms:endpointservice="test:MyProviderService"
endpoint="myProvider"role="provider"soap="true"
destinationStyle="queue"jmsProviderDestinationName="queueB"
connectionFactory="#connectionFactory">
<jms:endpoints>
</jms:component>
</sm:component>
</sm:activationSpec>
ProtocolBridgeAprotocolbridgeisanintegrationpatterntoconnectbetweentwodifferentprotocols.Forexample,HTTPandJMSaretwodifferenttransportprotocols.Iftherewasawaytobridgethesetwo,wecouldleveragethebestofbothworlds(openstandardnatureofHTTPandreliabletransportfeatureofJMS).Typically,itisnotstraightforwardtoconnecttwodifferentprotocolsandexchangeinformation.Weneedtoconnectindividual,correspondingchannelsspeakingdifferentprotocolsinthemessagingsystem.Thisisdemonstratedinthefollowingfigure:
Aprotocolbridgecanbeviewedasacombinationofchanneladapters.Anadaptercanfunctionasaclienttothemessagingsystem.Withtheclientrole,theadaptorcaninvokeapplicationfunctionsthroughtheapplicationsuppliedinterfaces.ThusaHTTPchanneladaptercanbeusedtoaccesstheHTTPservice
andpublishmessagesonaJMSchannel.Similarly,thesameadaptercanalsoreceivemessagesfromtheJMSchannelandinvokethefunctionalityovertheHTTPservice.
Alongthoselines,wecannowthinkofawebserviceadaptertotranslatebetweentheHTTP-basedwebserviceandtheJMS-basedmessagingsystem.Bydoingso,theSOAPformattedmessagescanberoutedthroughthetraditionalHTTPchannelthroughfirewallsovertheInternet,andalsothroughthemessagingchannelovertheintranetforaccessbyinterdepartmentalsystems.
Forexample,youcanthinkofascenariowhereanenterpriseprovidesa"ProductQuery"serviceoran"InventoryUpdate"service.SuchservicescanbeaccessedbyinterdepartmentalorLOBsystemssuchasthe"OrderEntry"systemor"Shipping"systemoverJMS.IftheenterprisewantstoexposetheseservicesoverthefirewallforB2Binteractionwithotherenterprises,theycandosointheSOAPoverHTTPstyleofinteraction.Forboththesetwotypesofinteraction,wedon'tneedtodefinetwoseparateservices.Instead,usinganadapter,thesameservicecanbemadeaccessiblethroughmultiplechannels.ThewebservicesgatewayprovidedbytheIBMWebsphereApplicationserverisafirstclassexampleofawebserviceadapter.
WebServiceintheJMSChannelBindingSampleWewillnowlookatacompletesampleofhowtobindawebserviceusingtheJMSchanneltoServiceMix.Whiledoingso,wewillalsoseehowtousethe
ApacheAxisclient-sideAPIstosendarequesttoandreceivearesponsefromthewebservice,throughtheJMSchannelratherthanthenormalHTTPchannel.WemaynotconfigurealloftheQOSfeaturesfortheJMSproviderheresuchastransaction,messagepersistence,orguaranteeddelivery.MostofthemareoutsidethestandardJ2EEconfigurationsandhavetobedoneattheJMSprovider-levelbasedonthevendor-specificmechanisms.SincethisbookisaboutJBIandServiceMixandnotJMS,wewillconcentrateonlyonthebindingpart.OncewearesuccessfulinbindingthewebservicetoJMS,thenenablingotherQOSfeaturesissimilartowhatwedointhenormalJMSconfigurations.
ServiceMixComponentArchitecturefortheJMSWebServiceWewillfirstlookatthetechnicalarchitectureforthewholecomponentsetuptoseehowwecanroutemessagesthroughvariousServiceMixcomponents.Themajorpartiesorrolestakingpartintheexchangeareasfollows:
Externalclient(sendingrequestandacceptingresponse).
JMSconsumer(requestqueueforclient).
Pipelinebridge.
HTTPprovider.
Externalwebservice.
JMSprovider(responsequeueforclient).
Asweknow,allthecomponentsareboundappropriatelytotheNMRandallthemessageexchangestakeplacethroughtheNMR.Thefollowingfigureshowsthecomponentarchitecture:
Asshownintheabovefigure,whentheclientsendsamessage,themessage-flowthroughtheNMRthroughvariousJBIcomponentsaremarkedbynumbersinsequence.YoumaynotethedynamicsofthePipelinecomponentinthepreviousfigure.Here,thePipelinewillsendtheinputmessageinanIn-OutMEPtotheHTTPProviderdestinationandtheninturnforwardtheresponseinanIn-OnlyMEPtotheJMSProvider.
Anaspecttonoticeintheabovearchitectureisthatthewholeinteractionisinarequest-responsestylefromtheconsumer(client)perspective.However,atthetransport-levelweimplementthisasacombinationofaIn-Onlyrequestanditscorrespondingresponse.
Letusnowsetuptheindividualcomponentsshowninthetechnicalarchitecture
figure.
DeploytheWebServiceAsafirststep,ifyouhaven'tdoneitbefore,editexamples.PROPERTIES(providedalongwiththecodedownloadforthischapter),andchangethepathstheretomatchyourdevelopmentenvironment.ThecodedownloadforthischapteralsoincludesaREADME.txtfile,whichgivesthedetailedstepstobuildandrunthesamples.
Wehaveasimplewebserviceinthecodebasepresentinthefolderch11\WebServiceInJmsChannel\01_ws.Todeploythewebservice,firstchangethedirectorytoch11\WebServiceInJmsChannel\01_wsandexecuteantasshownasfollows:
cdch11\WebServiceInJmsChannel\01_ws
ant
Thewebservicewillbecompletelybuiltandthewarfilecanbefoundinthefolder:ch11\WebServiceInJmsChannel\01_ws\dist\AxisEndToEnd.wa
r.
Todeploythewebservice,justdropthiswarfileintoyourfavoritewebserver'swebappsfolderandrestartthewebserver,ifnecessary.
Nowtomakesurethatyourwebservicedeploymentworksfine,wehaveprovidedtwotestclients.Toinvokethetestclientrunthefollowingcommands:
cdch11\ServiceMixHttpBinding\01_ws
antrun
and/or
anttest
WecanalsocheckthewebservicedeploymentbyaccessingtheWSDLfromthefollowingURL:http://localhost:8080/AxisEndToEnd/services/HelloWebSe
rvice?WSDL
Thetop-levelfolder,thatisch11\WebServiceInJmsChannel,willhaveasinglebuild.xmlfilewhichwillbuildallthesubprojectsinasinglego.Tobuildtheentiresample,changedirectorytothisfolderandexecuteantasfollows:
cdch11\WebServiceInJmsChannel
ant
XBean-basedservicemix-jmsBindingForXBean-baseddeploymentofservicemix-jms,ourxbean.xmlfilelookslikethefollowing:
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns:jms="http://servicemix.apache.org/jms/1.0"
xmlns:test="http://AxisEndToEnd.axis.apache.binildas.com">
<classpath>
<location>.</location>
</classpath>
<beanid="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<propertyname="brokerURL"value="tcp://localhost:61616">
<bean>
<jms:endpointservice="test:MyConsumerService"
endpoint="myConsumer"role="consumer"soap="true"
targetService="test:pipeline"
defaultMep="http://www.w3.org/2004/08/wsdl/in-only"
destinationStyle="queue"jmsProviderDestinationName="queue/A"
connectionFactory="#connectionFactory">
<jms:endpointservice="test:MyProviderService"
endpoint="myProvider"role="provider"soap="true"
destinationStyle="queue"jmsProviderDestinationName="queueB"
connectionFactory="#connectionFactory">
<beans>
Perhaps,youmighthavenoticedthefactthatfortheaboveconsumerrolethetargetServiceisnottheactualwebservice,butapipelinewhichisexplainednext.
XBean-basedservicemix-eipPipelineBridgeThepipelinecomponentisanintegrationbridgebetweenanIn-Only(orRobust-In-Only)MEPandanIn-OutMEP.ByreceivinganIn-OnlyMEPbythepipeline,wewillsendtheinputmessageinanIn-OutMEPtothetransformerdestinationandtheninturnforwardtheresponseinanIn-OnlyMEPtothetargetdestination.ThepipelineisastandardEIPcomponentandhenceisavailablereadilyasastandardJBIEIPcomponentinServiceMix.
ThepipelineEIPcomponentcanbeconfiguredusingXBeananddeployed.Theconfigurationxbean.xmlfileisasshownasfollows:
<beansxmlns:http="http://servicemix.apache.org/http/1.0"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:test="http://AxisEndToEnd.axis.apache.binildas.com">
<classpath>
<location>.</location>
</classpath>
<eip:pipelineservice="test:pipeline"endpoint="pipeline">
<eip:transformer>
<eip:exchange-targetservice="test:IHelloWebService">
<eip:transformer>
<eip:target>
<eip:exchange-targetservice="test:MyProviderService">
<eip:target>
</eip:pipeline>
</beans>
XBean-basedservicemix-httpProviderDestinationWenowrequireanIn-OutMEP-basedtargettransformerasthemessagedestination.Sinceourtargetserviceisawebservice,itmakessensetouseaservicemix-httpcomponentintheproviderroletopointtotheexternalwebservice.Thexbean.xmlconfigurationisasfollows:
<beansxmlns:http="http://servicemix.apache.org/http/1.0"
xmlns:test="http://AxisEndToEnd.axis.apache.binildas.com">
<classpath>
<location>.</location>
</classpath>
<http:endpointservice="test:IHelloWebService"
endpoint="HelloWebService"role="provider"
locationURI="http://localhost:8080/AxisEndToEnd/
ervices/HelloWebService"soap="true"soapAction=""
wsdlResource="http://localhost:8080/AxisEndToEnd/
services/HelloWebService?WSDL">
<beans>
DeployingtheSampleandStartingServiceMixTodeploytheServiceMixsample,wehavethefollowingservicemix.xml:
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:test="http://AxisEndToEnd.axis.apache.binildas.com">
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml"/>
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"value="classpath:servicemix.properties"
>
<bean>
<sm:containerid="jbi"MBeanServer="#jmxServer"
useMBeanServer="true"createMBeanServer="true"rootDir="./wdir"
installationDirPath="./install"deploymentDirPath="./deploy"
flowName="seda">
<sm:activationSpecs>
</sm:activationSpecs>
</sm:container>
</beans>
TobringupServiceMix,changedirectorytoch11\WebServiceInJmsChannelandbringuptheServiceMixcontainer.
cdch11\WebServiceInJmsChannel
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
TestWebServiceUsingJMSChannelTotestthewebservicedeployedsendingmessagesthroughJMSchannel,wewillhavetwoapproachesasfollows:
TestusingJMSclient—documentstyle:Thisapproachissimpleandstraightforward.WecancreateasimpleJMSclientwhichcanplaceaSOAPrequestdocumentintheinputqueue.Thesameclientwillalsolistentoanoutputqueuesothatwhenever(withinatimelimit)aresponsemessageisreceivedbackinthisqueuethentheclientcanconsumeit.
publicclassJMSClient
webservicetesting,documentstyle{
publicstaticStringMESSAGE_1="<?xmlversion=\"1.0\"
encoding=\"UTF-8\"?>SOAPMessage...";
privatestaticfinallongWAIT_TIME=51000L;
publicstaticvoidmain(String[]args)throwsException
{
ActiveMQConnectionFactoryfactory=new
ActiveMQConnectionFactory("tcp://localhost:61616");
ActiveMQQueuepubTopic=newActiveMQQueue("queue/A");
ActiveMQQueuesubTopic=newActiveMQQueue("queue/B");
Connectionconnection=factory.createConnection();
Sessionsession=connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
MessageProducerproducer=session.createProducer(pubTopic);
MessageConsumerconsumer=session.createConsumer(subTopic);
connection.start();
producer.send(session.createTextMessage(MESSAGE_1));
TextMessagetextMessage=(TextMessage)consumer.receive(1000
10);
if(textMessage==null)
{
System.out.println("Responsetimedout.");
}
else
{
System.out.println("Responsewas:"+textMessage.getText());
}
System.out.println("Closing.");
connection.close();
}
}
TheJMSClientisplacedinthefolderch11\WebServiceInJmsChannel\03_BindJms\src.Theclientclasswasalreadycompiledwhenwebuiltthefullproject.Torunthetestclient,changedirectorytoch11\WebServiceInJmsChannel\03_BindJmsandexecuteantasfollows:
cdch11\WebServiceInJmsChannel\03_BindJms
antrun
TestusingAxisclient—RPCstyle:Inthepreviousexample,wefollowedapuredocument-orientedapproachtoinvokethewebserviceandgetbacktheresponse.DuetothefactthatthetransportchannelisJMSwhichisdetachedandasynchronous,wemaynotbeabletochangethestylefullyfromthedocument-orientedapproach.However,wecanmaketheinvocationclosetoanRPCstylebyusingtheApacheAxisserviceandcallingobjects.
WeneedtohavemultipleartifactstoinvokethewebserviceinRPCstyle,andtheyarelistedhereindetail:
JMSTestClientRPCWebService.java:Thisisthemainclientclassusedtoinvokethewebservice.Thisclassisplacedinthech11\WebServiceInJmsChannel\05_AxisClient\src\com\binildas\apache\a
xis\AxisEndToEndfolder.
publicclassJMSTestClientRPCWebService
{
publicstaticvoidmain(Stringargs[])throwsException
{
org.apache.axis.client.ServiceaxisServiceObj=new
org.apache.axis.client.Service();
org.apache.axis.client.CallaxisCall=
(org.apache.axis.client.Call)axisServiceObj.createCall();
axisCall.setOperationName("hello");
axisCall.addParameter("in0",org.apache.axis.
encoding.XMLType.XSD_STRING,javax.xml.rpc.ParameterMode.IN
);
axisCall.setReturnType(org.apache.axis.encoding.
XMLType.XSD_STRING);
org.apache.axis.client.Transporttransport=new
org.apache.axis.client.Transporttransport=new
JMSTransportForAxis();
axisCall.setTransport(transport);
axisCall.setProperty("REQUEST_QUEUE","queue/A");
axisCall.setProperty("RESPONSE_QUEUE","queue/B");
Stringres=(String)axisCall.invoke(newObject[]
{"Binil"});
System.out.println("res:"+res);
}
}
Aswecanseeinthecodelisting,wefirstcreateanAxisCallinstanceandsettheoperationname(whichisthemethodnameoftheremotewebservice)andtheinputparameterstoinvoketheoperation.WealsoneedtosetthereturntypedetailssothattheCallinstancecanunmarshallanyreturntyperecievedfromthetransportchanneltothesuitableJavatype.
ThenextimportantstepissettingthetransportclassfortheCallobject.Here,wesetaninstanceofJMSTransportForAxis,whichprovidesthegatewaytothetransportchannel.
JMSTransportForAxis.java:ThisclassextendstheApacheAxisTransportclass:
publicclassJMSTransportForAxisextendsorg.apache.axis.
client.Transport
{
publicJMSTransportForAxis()
{
transportName="JMSTransportForAxis";
}
}
client-config.wsdd:Thenextimportantpieceistheclient-config.wsdd,whichshouldbethereintheclasspathwhileweinvoketheJMSTestClientRPCWebServiceclass.Thisconfigurationisplacedinch11\WebServiceInJmsChannel\05_AxisClient\config.
<?xmlversion="1.0"encoding="UTF-8"?>
<deploymentname="defaultClientConfig"
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<transportname="http"
pivot="java:org.apache.axis.transport.http.HTTPSender">
<transportname="local"
pivot="java:org.apache.axis.transport.local.LocalSender">
<transportname="java"
pivot="java:org.apache.axis.transport.java.JavaSender">
<handlername="JMSSender"
type="java:org.apache.axis.transport.jms.JMSSender">
<transportname="JMSTransport"pivot="JMSSender">
<handlername="CustomJMSSender"
type="java:com.binildas.apache.axis.AxisEndToEnd.JMSSender"
>
<transportname="JMSTransportForAxis"pivot=
"CustomJMSSender">
<deployment>
Thelinestobenotedfromtheaboveconfigurationarereproducedasfollows:
<handlername="CustomJMSSender"
type="java:com.binildas.apache.axis.AxisEndToEnd.JMSSender"
>
<transportname="JMSTransportForAxis"pivot=
"CustomJMSSender">
IfweobservetheJMSTransportForAxisclass,wecanseethatthevalueofthesuperclass(Transport)field(transportName)issetas"JMSTransportForAxis".Intheclient-config.wsdd,wethenpivotCustomJMSSenderagainstJMSTransportForAxisvalue.Now,weagainmaptheCustomJMSSendertoacustomtransportsenderclassjava:com.binildas.apache.axis.AxisEndToEnd.JMSSender
JMSSender.java:ThisistheclasswheretheactualtransportplumbinghappensandthiscallisnotmuchdifferentfromtheJMSClientclasswealreadysawintheprevioustestinthesensethatwewillhaveaninputandanoutputqueuetoplacearequestandtoreadanyresponse.
publicclassJMSSenderextendsorg.apache.axis.handlers.
BasicHandler
{
publicvoidinvoke(org.apache.axis.MessageContextmsgContext)
throwsorg.apache.axis.AxisFault
{
try
{
webservice,classesJMSSender.javaActiveMQConnectionFactory
factory=newActiveMQConnectionFactory("tcp://
localhost:61616");
ObjectrequestDestination=msgContext.
getProperty("REQUEST_QUEUE");
ObjectresponseDestination=msgContext.
getProperty("RESPONSE_QUEUE");
ActiveMQQueuepubTopic=newActiveMQQueue((String)
requestDestination);
ActiveMQQueuesubTopic=newActiveMQQueue((String)
responseDestination);
Connectionconnection=factory.createConnection();
Sessionsession=connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Sessionsession=connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
MessageProducerproducer=session.createProducer(pubTopic);
MessageConsumerconsumer=session.createConsumer(subTopic);
connection.start();
StringreqSOAPMsgString=msgContext
getRequestMessage().getSOAPPartAsString();
producer.send(session.createTextMessage(reqSOAPMsgString));
TextMessagem=(TextMessage)consumer.receive(1000*10);
StringrespMessageStr=null;
if(m==null)
{
System.out.println("Responsetimedout.");
}
else
{
respMessageStr=m.getText();
System.out.println("Responsewas:"+respMessageStr);
}
System.out.println("Closing.");
connection.close();
org.apache.axis.MessagerespSoapMessage=new
org.apache.axis.Message(respMessageStr);
msgContext.setResponseMessage(respSoapMessage);
}
catch(Exceptione)
{
throwneworg.apache.axis.AxisFault("failedSend",e);
throwneworg.apache.axis.AxisFault("failedSend",e);
}
}
}
Thepreviousprojectbuildhasalreadybuiltallthesubprojects,includingtheonecontainingalltheaboveclientclasses.So,torunthisclient,weneedtochangefoldertoch11\WebServiceInJmsChannel\05_AxisClientandexecuteantasfollows:
cdch11\WebServiceInJmsChannel\05_AxisClient
antrun
SummaryMOMincludingJMSisagreatenablerforreliablecommunicationbetweencomponents,especiallywhenyoudothatinalooselycoupled(asynchronous)manner.JMSprovidestherequiredAPIsandprovider-levelSPIsforJavacomponentstointeractthroughMOM.Combiningthepowerofmessagingoverareliablechannelalongwiththeinteroperabilityofwebservicesprovidesusagreaterflexibilitywithconfidenceinmessagingcharacteristics.WebservicesoverJMSarepositionedinthisspaceanditisnothingnewsincewehavebeendoingthatformanyenterpriseclasstransactions.ThenewthinghereistheendlesspossibilitiesprovidedbytheESBarchitecturewhencombinedwithtestedandprovenEAIpatterns.Thisisdemonstratedinthischapterwithsamples.Andkeepreading—youaregoingtoseemorepracticalusagesoftheESBarchitecturesuchaswebserviceversioninginthecomingchapters.
Chapter12.JavaXMLBindingusingXStreamWhiletheJavaprogramminglanguageprovidesusameanstowriteportablecode,XMLcanbeusedtodefineportabledata.WeuseXMLextensivelytoformatdatainSOA-basedarchitectures.Moreover,todayallnewgenerationplatforms,frameworks,andevenlegacyplatformssuchasCOBOLandMainframesexhibitsupportforXMLformatteddata.
ServiceMixisallaboutSOIandhenceitisalsoconcernedwithportabledata.Naturally,theformatofdatainsidetheNMRisXML.AnotheraspectisthatServiceMixisaJava-basedJBIframework.Hence,thedevelopersneedtowritecodeinJava,whethertheyareSEsorBCs.ItisinthiscontextthattherelationshipbetweenJavaandXMLintheServiceMixcontextneedsattention.
ThischapterwillprovideabriefintroductiontoJavaXMLbindingandtotheconceptsandtechnologiesthatitemploys.
Sowewillcoverthefollowinginthischapter:
JavaXMLbindingingeneral
JavaXMLbindingframeworksincludingXStream
XStreamintegrationwiththeServiceMixESB
WorkingcodesampleshowingXStreaminactioninServiceMix
JavaXMLBindingJavaXMLbindingdealswithtransformingtheXMLinstancestotheJavainstancesandviceversa.EventhoughwecandothisbywritingJavacodefromscratchagainsttheXMLAPIs,todaywehavemultipletoolsandframeworkswhichwilldothesame.
TheabovefigureshowsatypicalscenariowemightcomeacrossinB2Binteractions.LeavetheadvancedvalidationsorCRUDoperationsonecandointheXMLdocumentsalone,weareinterestedinthemarshallingandunmarshallingfunctionalityoftheJAXB.XMListhede-factowireformatinSOAandSOI.IfweneedtoprocesstheXMLdatafromwithinourJavacomponents,wehavetodosomeformofXMLbinding.TheframeworkssuchasCastorandXMLBeansdoexactlythis.JAXBistheJavareferenceimplementationforJavaXMLbinding.Today,wehaveXStreamwhichwilldothesamefunctionalityquickly.Letusseehowthese
frameworksarerelevantintheJBIdiscussion.
JAXBJavaAPIforXMLBinding(JAXB)providesaconvenientwaytoprocessXMLcontentusingJavaobjectsbybindingitsXMLschematoJavarepresentation.JAXBprovidesanAPIandtherequiredtoolsetsthatautomatethemappingbetweentheXMLdocumentsandtheJavainstances.Thuswecanlistoutthemainfeaturesas:
UnmarshaltheXMLinstanceintoaJavainstance.
Access,update,andvalidatetheJavarepresentationagainstschemaconstraint.
MarshaltheJavainstanceoftheXMLcontentintotheXMLdocumentinstance.
XStreamXStreamisasimple,opensourcelibrarytoserializeJavaobjectstotheXMLandbackagain.Itislightweightinthesensethatitdoesn'trequiremuchconfigurationormappingfiles.XStreamhasagoodintegrationwiththeServiceMix.Infact,ServiceMixprovidesanXStreambackedAPIitselfnamedJavaSource.
ThemainfeaturesofXStreamarelistedasfollows:
Easeforuse:Ahigh-levelfacade-classcalledXStreamissuppliedwhichsimplifiesthecommonusecases.
Nomappingsrequired:Mostobjectscanbeserializedbyregisteringtheir
class.
Performance:XStreamissuitableforlargeobjectgraphsorsystemswithhighmessagethroughput.
Worksonnormalobjects:Serializesinternalfields,includingprivateandfinal.Supportsnon-publicandinnerclasses.Theclassesarenotrequiredtohaveadefaultconstructor.
Fullobjectgraphsupport:Duplicatereferencesencounteredintheobject-modelwillbemaintained.Supportscircularreferences.
IntegrateswithotherXMLAPIs:Byimplementingsuitableinterfaces,XStreamsupportsserializationdirectlytoorfromanytreestructureincludingXML.
LetusalsolookatasamplebindingusingXStream.ConsiderthefollowingtwoclassesnamelytheCustomerandtheContact:
publicclassCustomer
{
privateStringfirstName;
privateStringlastName;
privateContactphone;
}
publicclassContact
{
privateintcode;
privateStringnumber;
}
Now,ifyouhavetouseXStreamtoconverttheaboveentitiestoXML,thenfirstinstantiatetheXStreamfaçadeandcreatealiasesforyourcustomclassnamestoXMLelementnamesasshowninthefollowingcode:
XStreamxStream=newXStream();
XStreamxStream=newXStream();
xStream.alias("customer",Customer.class);
xStream.alias("contact",Contact.class);
Nowitisamatterofcreatingtheentitytree,populatingitsfields,andthencallingthetoXMLmethodinXStream.Thisisreproducedinthefollowingcode:
Customerbinil=newCustomer("Binil","Das");
binil.setPhone(newContact(91,"471-2700888"));
Stringxml=xStream.toXML(binil);
TheXMLoutputwilllooklikethis:
<customer>
<firstname>Binil</firstname>
<lastname>Das</lastname>
<phone>
<code>91</code>
<number>471-2700888</number>
</phone>
</customer>
ToreconstructtheobjecttreebackfromXMLiseasy,andisshownasfollows:
CustomerbinilBack=(Customer)
xstream.fromXML(xml);
ServiceMixandXStreamServiceMixhasgoodintegrationwithXStreamasa
mechanismforXMLtoJavabindingandviceversa.ThisismadepossibleinServiceMixbyexposingafewAPIs,themainonesarelistedasfollows:
org.apache.servicemix.jbi.messaging.DefaultMarshaler
org.apache.servicemix.components.util.xstream.XStreamMarshaler
org.apache.servicemix.components.util.xstream.XStreamSource
org.apache.servicemix.JavaSource
Therelationshipbetweentheseclasseswithcom.thoughtworks.xstream.XStreamisshowninthefollowingfigure:
Now,ifweneedtointegratewithXStreaminourcustomtransformationcomponents,wecandosobycreatinganinstanceofXStreamSource.
XStreamxStream=newXStream();
xStream.alias("ServiceParamTO",
ServiceParamTO.class);
xStream.alias("CustomerTO",CustomerTO.class);
//Registerotherclasses…
JavaSourceJavaSource=new
JavaSourceJavaSource=new
XStreamSource(payLoad,xStream);
Now,wejustsetthisinstanceofXStreamSourceastheinmessagetotheinOutmethodandsendthemessageexchange.
normalizedMessageIn.setContent(javaSource);
inOut.setInMessage(normalizedMessageIn);
sendSync(inOut);
Asyouknow,theNMRofServiceMixalwaysdealswiththenormalizedmessageformat,whichistheXMLformat.TherequiredplumbingwillbedonebytheXStreaminthebackground.
XStreaminaNormalizedMessageRouterSampleInChapter7,youhavelearnthowtocodeandbuildcustomcomponentstobedeployedintheServiceMixcontainer.ThereweusedanHttpInterceptorclasstointerceptthecontentsoftheJBIexchangeandprintthemoutontheconsole.WewillenhancethecodefromthatsampletodemonstratehowwecanintegrateXStreamwithotherJBIclassesinServiceMix.
SampleUseCase
IntheSOAscenarios,weusetheXMLformattedmessagestotransportpayloadacrossnodes.WhetherSOAPformattedornot,XMLprovidesaflexiblemechanismtotransportdata,whichcanbevalidatedifrequiredusingtheXMLschemas.Letusalsobuildoursamplearoundthis.Hence,wewillassumethatwehaveanexternalclientsendinganXMLpayloadtotheESB.Letusseehowwecaninteractwiththisdatainsidethebus.
Thisisdiagrammaticallyrepresentedinthefollowingfigure:
Thesampleusecasewillconsistofthefollowingcomponents:
HTTPClient:TheHTTPClientisaclientexternaltotheESBwhichinteractwiththeHTTPConnectorinsidetheESBtosendtherequestmessageandgettheresponseback.
HTTPConnector:TheHTTPConnectorisaServiceMixHttpConnectorcomponentconfiguredtolistentoaspecificport.AnymessagesarrivingattheHTTPConnectorwillbedirectedtothenextcomponentintheflow,namelytheHTTPInspector.
HTTPInterceptor:TheHTTPInterceptorisaServiceMixTransformComponent.Thiscomponent,asthenameimplies,willfirstinterceptthemessagecontents.TheXMLformattedmessagesentbytheHTTPClientwillbeinterceptedhere,andthenprintedouttotheconsole.WethenunmarshaltheXMLinstanceintoaJavainstanceusingtheXStream.Nextcomesthekeysequenceinthissample—wesettheJavainstanceintotheInOutofthemessageexchangeinthenextchainoftheinteraction,tobesenttothedestinationservice,XStreamInspector.
XStreamInspector:InXStreamInspector,wetrytoretrievebackthemessagecontentandprintittotheconsole.ThenXStreamInspectorsendsthesameXMLcontentbacktotheHTTPInterceptor.
Inthereversestreamflow,atHTTPInterceptorweagainprintoutthecontentreceivedfromtheXStreamInspectortotheconsole,andthensendbackthesameXMLtotheHTTPClient.
Thefollowingfigurelistshowthevariouscodeartifactsforthesampleareorganized:
CodeHTTPClientHTTPClientisanormalHTTPClientandiscodedinthefilech12\JavaXmlBinding\Client.html.ThiscomponentiscapableofsendingthefollowingXMLrequesttotheURL:http://localhost:8912.
<?xmlversion="1.0"encoding="UTF-8"?>
<env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tns="http://servicemix.apache.org/samples/wsdl-
xmlns:tns="http://servicemix.apache.org/samples/wsdl-
first/types">
<env:Body>
<ServiceParamTO>
<customerTO>
<firstName>Ann</firstName>
<lastName>Binil</lastName>
<addressTO>
<houseNumber>222</houseNumber>
<street>LakeView</street>
<city>Cochin</city>
</addressTO>
</customerTO>
<creditCardTO>
<cardNumber>8888-9999-1111-2222</cardNumber>
<validTill>01-APR-2007</validTill>
<cardType>MasterCard</cardType>
</creditCardTO>
</ServiceParamTO>
</env:Body>
</env:Envelope>
UnmarshallingtoTransferObjectsWehaveasetofJavaTOclassessothattheXStreamcanunmarshaltheaboveXMLdocumenttotheTOinstancesandbacktotheXMLwheneverrequired.Thisisshowninthefollowinglist:
ch12\JavaXmlBinding\src\com\binildas\esb\javasource\ServiceParamTO.java
publicclassServiceParamTOimplements
Serializable
{
privateCustomerTOcustomerTO;
privateCreditCardTOcreditCardTO;
}
ch12\JavaXmlBinding\src\com\binildas\esb\javasource\CustomerTO.java
publicclassCustomerTOimplements
Serializable
{
privateStringfirstName;
privateStringlastName;
privateAddressTOaddressTO;
}
ch12\JavaXmlBinding\src\com\binildas\esb\javasource\AddressTO.java
publicclassAddressTOimplements
Serializable{
privateStringhouseNumber;
privateStringstreet;
privateStringcity;
}
ch12\JavaXmlBinding\src\com\binildas\esb\javasource\CreditCardTO.java
publicclassCreditCardTOimplements
Serializable{
privateStringcardNumber;
privateStringvalidTill;
privateStringcardType;
}
TheseclassesarerelatedasshowninthefollowingUMLclassdiagram:
HttpInterceptorComponentTheHttpInterceptorisaServiceMixTransformcomponent.Thiscomponentwillfirstinterceptthemessagecontents.TheXMLformattedmessagesentbytheHTTPclientwillbeinterceptedhere,andthenprintedouttotheconsole.WethenunmarshaltheXMLinstanceintoaJavainstanceusingXStream.TheJavainstanceisthensentthroughtheNMRtothenextcomponentintheflow,whichistheXStreamInspector.Letuslookintothecodeshownasfollows:
publicclassHttpInterceptorextends
TransformComponentSupport
{
protectedbooleantransform(MessageExchange
exchange,NormalizedMessagein,NormalizedMessage
out)throwsMessagingException
{
System.out.println("HttpInterceptor("+name+
").transform01.exchange.getService()="+
exchange.getService());
XStreamxStream=null;
StringcontentString=null;
ServiceParamTOpayLoad=null;
ServiceParamTOpayLoad=null;
JavaSourcejavaSource=null;
QNameservice=null;
InOutinOut=null;
NormalizedMessagenormalizedMessageIn=null;
NormalizedMessagenormalizedMessageOut=null;
NormalizedMessagecopyReturnMessage=null;
SourcecontentReturn=null;
InputStreaminputStream=null;
byte[]bytes=null;
intavailable=0;
StringcontentReturnString=null;
NormalizedMessagecopyMessage=
exchange.createMessage();
getMessageTransformer().transform(exchange,in,
copyMessage);
Sourcecontent=copyMessage.getContent();
if(contentinstanceofDOMSource){
contentString=
XMLUtil.retreiveSoapContent(((DOMSource)
content).getNode());
System.out.println("HttpInterceptor("+name+
").transform02.contentString="+
contentString);
payLoad=(ServiceParamTO)
XStreamUtil.xmlToObject(contentString);
xStream=newXStream();
xStream.alias("ServiceParamTO",
ServiceParamTO.class);
xStream.alias("CustomerTO",CustomerTO.class);
xStream.alias("CreditCardTO",
CreditCardTO.class);
xStream.alias("AddressTO",AddressTO.class);
javaSource=newXStreamSource(payLoad,xStream);
service=newQName(namespaceURI,localPart);
inOut=createInOutExchange(service,null,null);
normalizedMessageIn=inOut.createMessage();
normalizedMessageIn.setContent(javaSource);
inOut.setInMessage(normalizedMessageIn);
sendSync(inOut);
normalizedMessageOut=inOut.getOutMessage();
copyReturnMessage=exchange.createMessage();
copyReturnMessage=exchange.createMessage();
getMessageTransformer().transform(exchange,
normalizedMessageOut,copyReturnMessage);
contentReturn=copyReturnMessage.getContent();
if(contentReturninstanceofStringSource)
{
try
{
inputStream=((StringSource)contentReturn).
getInputStream();
available=inputStream.available();
bytes=newbyte[available];
inputStream.read(bytes);
}
catch(IOExceptionioException)
{
thrownewMessagingException(ioException);
}
contentReturnString=newString(bytes);
System.out.println("HttpInterceptor("+name+
").transform03.contentReturnString="+
contentReturnString);
out.setContent(contentReturn);
System.out.println("HttpInterceptor("+name+
").transform04.contentReturnString="+
contentReturnString);
}
System.out.println("HttpInterceptor("+name+
").transform05.End");
}
returntrue;
}
}
Inthecode,wecreateaninstanceofXStreamandregisterallTOclassestoXStream.ThenusingthisXStreaminstanceandtheXMLpayload,wecreateaninstanceofXStreamSource.TheXStreamSourceinstanceisa
JavaSourcetype,whichagainisajavax.xml.transform.Sourcetype.ThismakesiteasyforustosetthisJavaSourceintotheInOutofthemessageexchangeinthenextchainoftheinteraction,tobesenttothedestinationservicewhichisXStreamInspector.
XStreamInspectorComponentComparedtoHttpInterceptor,theXStreamInspectorclassissimple.Itretrievesbackthemessagecontentandprintsittotheconsole.TheXStreamInspectorclassthensendsthesameXMLcontentbacktoHttpInspector.
publicclassXStreamInspectorextends
TransformComponentSupport
{
protectedbooleantransform(MessageExchange
exchange,NormalizedMessagein,NormalizedMessage
out)throwsMessagingException
{
System.out.println("XStreamInspector("+name+
").transform01.exchange.getService()="+
exchange.getService());
NormalizedMessagecopyMessage=
exchange.createMessage();
getMessageTransformer().transform(exchange,in,
copyMessage);
Sourcecontent=copyMessage.getContent();
StringcontentString=null;
if(contentinstanceofDOMSource)
{
contentString=
XMLUtil.node2XML(((DOMSource)content).
XMLUtil.node2XML(((DOMSource)content).
getNode());
System.out.println("XStreamInspector("+name+
").transform02.contentString="+
contentString);
}
out.setContent(newStringSource(contentString));
System.out.println("XStreamInspector("+name+
").transform03.End");
returntrue;
}
}
ConfigureInterceptorandInspectorComponentsWecanconfiguretheHttpInterceptorandXStreamInspectorcomponentsinasingleSU.Hence,wewilldotheconfigurationofthesecomponentsasanSUintheservicemix.xmlfilekeptatch12\JavaXmlBinding\su\servicemix.xml.
Thecontentsofthisfileisshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:demo="http://www.binildas.com/esb/LightWeightOrPojo">
<classpath>
<location>.</location>
</classpath>
<sm:serviceunitid="jbi">
<sm:activationSpecs>
<sm:activationSpeccomponentName="interceptor"
endpoint="interceptor"
service="demo:interceptor">
<sm:component>
<beanclass="com.binildas.esb.
javasource.HttpInterceptor">
<propertyname="name">
<value>Interceptor-1</value>
</property>
<propertyname="namespaceURI">
<value>
http://www.binildas.com/esb/LightWeightOrPojo
</value>
</property>
<propertyname="localPart">
<value>inspector</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="inspector"
endpoint="inspector"service="demo:inspector">
<sm:component>
<beanclass="com.binildas.esb.javasource.
XStreamInspector">
<propertyname="name">
<value>Inspector-1</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:serviceunit>
</beans>
PackageInterceptorandInspector
ComponentsWewillcreateanSUandthenpackageitintoanSA.WehavealreadyseentheSUconfiguration,letusnowlookintotheSAconfigurationat:
ch12\JavaXmlBinding\sa\META-INF\jbi.xml
Thejbi.xmlfileisreproducedinthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<jbixmlns="http://java.sun.com/xml/ns/jbi"
version="1.0">
<service-assembly>
<identification>
<name>InterceptorAssembly</name>
<description>InterceptorService
Assembly</description>
</identification>
<serviceunit>
<identification>
<name>Interceptor</name>
<description>InterceptorService
Unit</description>
</identification>
<target>
<artifacts-zip>Interceptor-su.zip</artifacts-zip>
<component-name>servicemix-
lwcontainer</component-name>
</target>
</serviceunit>
</service-assembly>
</jbi>
DeployInterceptorandInspectorComponentsThemainpointtobenotedintheSAjbi.xmlisthetargetelementoftheserviceunit.HerewespecifythattheSUartifact(thatisInterceptor-su.zip)istobedeployedintotheservicemix-lwcontainertargetcontainer.
Todothis,wehaveservicemix.xmlfileinthetopmostfoldertostarttheServiceMixcontainer.Thisisshownasfollows:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:demo="http://www.binildas.com/esb/LightWeightOrPojo">
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<sm:containerid="jbi"rootDir="./wdir"
installationDirPath="./install"
deploymentDirPath="./deploy"flowName="seda"
monitorInstallationDirectory="true"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpeccomponentName="httpReceiver"
service="bt:httpBinding"endpoint="httpReceiver"
destinationService="demo:interceptor">
<sm:component>
<bean
class="org.apache.servicemix.components.http.
HttpConnector">
<propertyname="host"value="127.0.0.1"/>
<propertyname="port"value="8912">
<bean>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
</beans>
HereyoucanseethatweconfigureanHttpConnectortolistenatport8912.ItistothistargetthattheHTTPClientsendstheXMLrequest.
BuildandRuntheSampleAsafirststep,ifyouhaven'tdoneitbefore,editexamples.PROPERTIES(providedalongwiththecodedownloadforthischapter),andchangethepathstheretomatchyourdevelopmentenvironment.ThecodedownloadforthischapteralsoincludesaREADME.txtfile,whichgivesdetailedstepstobuildandrunthesamples.
Tobuildandrunthesample,firstchangedirectorytoch12\JavaXmlBindingfolderandexecuteantasshownhere:
cdch12\JavaXmlBinding
ant
WecanbringupServiceMixbyrunningthefollowingcommands:
cdch12\JavaXmlBinding
%SERVICEMIX_HOME%/bin/servicemixservicemix.xml
WhenwestartServiceMix,theJBIcontainerisconfiguredusingtheaboveservicemix.xmlfile.
Torunthedemo,thereisaClient.htmlfileprovidedinthetop-levelfolder.
SummaryYouhavealreadydeployedPOJOcomponentsintoServiceMixandexposedthemasservices.AnexternalclientcaninvokethePOJOservicesbysendingSOAPrequestsandreceivingbacktheSOAPresponses.Attimes,youmayalsoneedtodealwithnon-SOAPformatted,butplainXMLmessages.Wealsoneedtostreamsuchmessagestoothroughfirewallstothebusandgetthemprocessed.
ThischaptershowedyouhowwecandothisusingXStream.Somelegacyintegrationscenariomightwarrantthisapproach.YoumightalsohavenotedthefactthatwecanreplacetheXStreamusedinthissamplewithanyotherJavaXMLbindingframeworksuchasCastororXMLBeans,butXStream'sadvantageisthebuilt-inintegrationXStreamhas
withtheServiceMixJBI.
TheServiceMixJBIbusprovidesaframeworkformanylightweightintegrationlibrarieslikeXStream.ItalsorealizesmanydesignpatternsusedinsoftwareengineeringlikethewellknownProxypatternwhichwewillexploreinthenextchapter.
Chapter13.JBIProxyOneofthemostusefulclassesintroducedbyJDK1.3istheProxyclassinthejava.lang.reflectpackage.Itallowsustocreateclassesimplementingaparticulartype(interface)onthefly.ServiceMixprovidesasimilarAPIinJBIsothatwecanproxyaparticularserviceintheJBIbus.Thishelpsustoimplementmanyfunctionalitiessuchas:
Interceptingandre-routingtheservices.
Wrappingandunwrappingmessagestargetedtoaservice.
Usingrequest-message,formattedforaparticularservicetype,foradifferentservicetype.
Inthischapter,wewillfirstrevisitJDKProxyclasses.ThiswillsetabackgroundforfurtherreadingwhereinwewillexplainJBIProxyindetailwithexamplesformultiplescenarios.ThenthedeveloperwillbeabletomakeuseofProxypatternwithintheJBI-basedESB,tosuittheirtechnicalrequirements.
Wewillcoverthefollowinginthischapter:
Proxydesignpatterningeneral
ProxysupportinJavaSDKwithexamples
ServiceMixJBIProxy
AfewsamplesofdefiningandexposingproxiestoservicesintheJBIbus
ApracticaluseofJBIProxy—toproxyexternalwebservicesintheJBIbus
Proxy—APrimerWikipediadefinesProxyas:
Proxymayrefertosomethingwhichactsonbehalfofsomethingelse.
Inthesoftwareaproxyisasubstituteforatargetinstanceandisageneralpatternwhichappearsinmanyotherpatternsindifferentvariants.
ProxyDesignPatternAproxyisasurrogateclassforthetargetobject.Ifamethodcallhastobeinvokedinthetargetobject,ithappensindirectlythroughtheproxyobject.Thefeaturewhichmakesproxyidealformanysituationsisthattheclientorthecallerisnotawarethatitisdealingwiththeproxyobject.Theproxyclassisshowninthefollowingfigure:
Intheabovefigure,whenaclientinvokesamethodtargettowardstheTargetservice,theproxyinterceptsthecallinbetween.Theproxyalsoexposeasimilarinterfacetothetarget,hencetheclientisunawareofthedealingwiththeproxy.Thustheproxymethodisinvoked.Theproxythendelegatesthecalltotheactualtargetsinceitcannotprovide
theactualfunctionality.Whendoingso,theproxycanprovidecallmanagementtowardstheactualmethod.Theentiredynamicsisshowninthefollowingfigure:
Aproxyisusuallyimplementedbyusingacommon,sharedinterfaceorsuperclass.Boththeproxyandthetargetsharethiscommoninterface.Then,theproxydelegatesthecallstothetargetclass.
JDKProxyClassJDKprovidesboththeclassProxyandtheinterfaceInvocationHandlerinthejava.lang.reflectpackage,sinceversion1.3.UsingJDKProxyclasses,youcancreateyourownclassesimplementingmultipleinterfacesofyourchoice,atruntime.
Proxyisthesuperclassforanydynamicproxyinstancesyoucreateatruntime.Moreover,theProxyclassalsoaccommodatesahostofstaticmethodswhichwillhelpyoutocreateyourproxyinstances.getProxyClassandnewProxyInstancearetwosuchutilitymethods.
TheProxyAPIislistedinthefollowinginbrevity:
packagejava.lang.reflect;
publicclassProxyimplements
java.io.Serializable
{
protectedInvocationHandlerh;
protectedProxy(InvocationHandlerh);
publicstaticInvocationHandler
getInvocationHandler(Objectproxy)throws
IllegalArgumentException;
publicstaticClass<?>getProxyClass(ClassLoader
loader,Class<?>...interfaces)throws
IllegalArgumentException;
publicstaticbooleanisProxyClass(Class<?>cl);
publicstaticObjectnewProxyInstance(ClassLoader
loader,Class<?>[]interfaces,InvocationHandler
h)throwsIllegalArgumentException
}
Intheabovecode,youcaninvoketheProxy.getProxyClasswithaclassloaderandanarrayofinterfacesforwhichyouneedtoproxy,togetaClassinstancefortheproxy.Proxyobjectshaveoneconstructor,towhichyoupassanInvocationHandlerobjectassociatedwiththatproxy.Whenyouinvokeamethodontheproxyinstance,themethodinvocationisencodedanddispatchedtotheinvokemethodofitsinvocationhandler.LetusalsolookattheInvocationHandlerAPIreproducedasfollows:
packagejava.lang.reflect;
publicinterfaceInvocationHandler
{
Objectinvoke(Objectproxy,Methodmethod,
Object[]args)throwsThrowable;
}
Weneedtoimplementthisinterfaceandprovidecodefortheinvokemethod.OnceyougetaClassinstancefortheproxybyinvokingtheProxy.getProxyClasswithaclassloaderandanarrayofinterfacesforwhichyouneedtoproxyto.Now,youcangetaConstructorobjectforthisproxyfromtheClassinstance.OntheconstructoryoucanusenewInstance(passinginaninvocationhandlerinstance)tocreatetheproxyinstance.ThecreatedinstanceshouldbeimplementingalltheinterfacesthatwerepassedtogetProxyClass.Thestepsareshowninthefollowingcode:
InvocationHandlerhandler=new
SomeInvocationHandler(...);
ClassproxyClazz=
Proxy.getProxyClass(Blah.class.getClassLoader(),
newClass[]{Blah.class});
Blahblah=(Blah)proxyClazz.getConstructor(new
Class[]{InvocationHandler.class
}).newInstance(newObject[]{handler});
Thereisalsoashortcuttogetaproxyobject.YoucaninvokeProxy.newProxyInstance,whichtakesaclassloader,anarrayofinterfaceclasses,andaninvocationhandlerinstance.
InvocationHandlerhandler=new
SomeInvocationHandler(...);
Blahblah=(Blah)
Proxy.newProxyInstance(Blah.class.
getClassLoader(),newClass[]{Blah.class},
getClassLoader(),newClass[]{Blah.class},
handler);
Nowyoucaninvokemethodsontheproxyobjectduringwhichthesemethodinvocationsareturnedintocallsontotheinvocationhandler'sinvokemethodisshownhere:
blah.interfaceMethod();
SampleJDKProxyClassWewillnowwritesomesimplecodetodemonstratehowyoucanwriteyourownproxiesatruntime,foryourinterfaceclasses.
Asafirststep,ifyouhaven'tdoneitbefore,editexamples.PROPERTIES(providedalongwiththecodedownloadforthischapter),andchangethepathstheretomatchyourdevelopmentenvironment.ThecodedownloadforthischapteralsoincludesaREADME.txtfile,whichgivesdetailedstepstobuildandrunthesamples.
Wewillnowlookatthesourcecodethatcanbefoundinthefolderch13\JdkProxy\src.
Thefilesareexplainedhere:
ch13\JdkProxy\src\SimpleIntf.java
publicinterfaceSimpleIntf
{
publicvoidprint();
}
}
SimpleIntfisasimpleinterfacewithasinglemethodprint.printdoesnotacceptanyparametersandalsodoesnotreturnanyvalue.OuraimisthatwhenweinvokemethodsontheproxyobjectforSimpleIntf,themethodinvocationshouldbeturnedintocallstoaninvocationhandler'sinvokemethod.Letusnowdefineaninvocationhandlerinthefollowingcode:
ch13\JdkProxy\src\SimpleInvocationHandler.java
importjava.lang.reflect.InvocationHandler;
importjava.io.Serializable;
importjava.lang.reflect.Method;
publicclassSimpleInvocationHandlerimplements
InvocationHandler,Serializable
{
publicSimpleInvocationHandler(){}
publicObjectinvoke(finalObjectobj,Method
method,Object[]args)throwsThrowable
{
if(method.getName().equals("print")&&(args==
null||args.length==0))
{
System.out.println("SimpleInvocationHandler.invoked");
}
else
{
thrownewIllegalArgumentException("Interface
methoddoesnotsupportparam(s):"+args);
}
returnnull;
}
}
SinceSimpleIntf.print()doesnotacceptanyparametersandalsodoesnotreturnanyvalue,intheinvokemethodofSimpleInvocationHandler,wedoublechecktheintentionbehindtheactualinvoker.Inotherwords,wecheckthatnoparametersarepassedandwereturnnullonly.
Now,wehaveallthenecessaryclassestoimplementaproxyforSimpleIntfinterface.LetusnowexecuteitbywritingaTestclass.
ch13\JdkProxy\src\Test.java
importjava.lang.reflect.Proxy;
importjava.lang.reflect.InvocationHandler;
publicclassTest
{
publicstaticvoidmain(String[]args)
{
InvocationHandlerhandler=new
SimpleInvocationHandler();
SimpleIntfsimpleIntf=
(SimpleIntf)Proxy.newProxyInstance
(SimpleIntf.class.getClassLoader(),newClass[]{
SimpleIntf.class},handler);
simpleIntf.print();
}
}
ThewiringoftheabovedescribedinterfacesandclassesarebetterrepresentedintheUMLclassdiagraminthefollowingfigure:
Theabovefigureshowstherelationshipbetweenvariousclassesandinterfacesinthesample.$Proxy0classrepresentstheactualproxyclassgeneratedontheflyandasyoucandeduceitfromtheclassdiagram.$Proxy0isatypeofourinterface(SimpleIntf).
Tobuildthesample,firstchangedirectorytoch13\JdkProxyandexecuteantasshownhere:
cdch13\JdkProxy
ant
ThecommandantrunwillexecutetheTestclasswhichwillprintoutthefollowingintheconsole:
ServiceMixJBIProxyJavaproxiesfortheJBIendpointscanbecreatedinServiceMixusingJSR181components.Forthis,therequirementisthattheJBIendpointsshouldexposeaWSDL.
Ajsr181:endpointtakesavaluefortheserviceInterfaceattribute.TheJBIcontainerwillbeabletogeneratetheWSDLoutofthisserviceInterface.Thus,ifwehaveajsr181:endpointexposingservicetotheJBIbus,itispossibletoprovideaproxyforthatservicetoo.
ThebasicconfigurationfordefiningaJBIproxyisshownasfollows:
<jsr181:proxyid="proxyBean"container="#jbi"
interfaceName="test:HelloPortType"
type="test.Hello"/>
Onceaproxyisdefined,thesamecanthenbereferencedfromyourclientbeanorfromoneofyourcomponents.Theproxied
JBIendpointcanthenbeinvokedjustlikeanormalPOJO.
IfyouwanttodefineaJBIproxywithinaSU,youcanfollowtheconfigurationgivenasfollows:
<jsr181:endpointannotations="none"
service="test:echoService"
serviceInterface="test.Echo">
<jsr181:pojo>
<beanclass="test.EchoProxy">
<propertyname="echo">
<jsr181:proxyservice="test:EchoService"
context="#context"type="test.IService">
<property>
</bean>
</jsr181:pojo>
</jsr181:endpoint>
Letusnowlookintoafewexamplestomaketheconceptclearer.
JBIProxySampleImplementingCompatibleInterfaceFirst,wewillcreateaJBIproxyimplementinganinterfacecompatiblewiththetargetservice.Then,inplaceofthetargetservicewewillusetheproxyinstance,sothatanycallsintendedforthetargetservicewillbefirstroutedtotheproxy.Theproxyinturnwilldelegatethecalltothetargetservice.
Thestructuralrelationshipbetweenvariousclassesparticipatingintheinteractionisshowninthefollowingfigure:
Here,EchoProxyServiceistheclasswhichwelaterexposeintheJBIbusastheservice.ThisclassimplementstheIEchointerface.Inordertodemonstratetheproxy,EchoProxyServicedoesn'timplementtheserviceassuch,insteaddependsontheJbiProxyderivedoutofanotherclassTargetService.TheTargetServicecontainstheactualservicecode.Asyoucansee,boththeEchoProxyServiceandtheTargetServiceimplementthesameinterface.
ProxyCodeListingThecodebaseforthesampleislocatedinthefolderch13\JbiProxy\
01_CompatibleInterface\01_JsrProxy\src.
ThisfoldercontainsaninterfaceIEchoandtwootherclassesimplementingtheIEchointerfacenamely
EchoProxyServiceandTargetService.Theseclassesareexplainedhere:
IEcho.java:TheIEchointerfacedeclaresasinglemethodechowhichtakesaStringparameterandreturnsaString.
publicinterfaceIEcho
{
publicStringecho(Stringinput);
}
EchoProxyService.java:EchoProxyServiceisaconvenientclasswhichwillactasmechanismforroutingrequeststotheJBIproxy.Moreover,EchoProxyServiceimplementstheaboveinterfaceIEcho.
publicclassEchoProxyServiceimplements
IEcho
{
privateIEchoecho;
publicvoidsetEcho(IEchoecho)
{
this.echo=echo;
}
publicStringecho(Stringinput)
{
System.out.println("EchoProxyService.echo.
this="+this);
returnecho.echo(input);
}
}
TargetService.java:TargetServicealsoimplementstheinterfaceIEcho.TargetServiceissupposedtobeourtargetservice,andwewillbegeneratingaJBIproxyfortheTargetService.
publicclassTargetServiceimplementsIEcho
{
publicStringecho(Stringinput)
{
System.out.println("TargetService.echo:
System.out.println("TargetService.echo:
String.this="+this);
returninput;
}
}
XBean-basedJBIProxyBindingUsingXBean,wewillnowconfiguretheJBIproxytobedeployedontothestandardservicemix-jsr181JBIcomponent.Thexbean.xmlisasshownasfollows:
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:jsr181="http://servicemix.apache.org/jsr181/1.0"
xmlns:http="http://servicemix.apache.org/http/1.0"
xmlns:test="http://test">
<classpath>
<location>.</location>
</classpath>
<jsr181:endpointannotations="none"
service="test:echoService"
serviceInterface="test.IEcho">
<jsr181:pojo>
<beanclass="test.EchoProxyService">
<propertyname="echo">
<jsr181:proxyservice="test:TargetService"
context="#context"type="test.IEcho">
<property>
</bean>
</jsr181:pojo>
</jsr181:endpoint>
<jsr181:endpointannotations="none"
service="test:TargetService"
serviceInterface="test.IEcho">
<jsr181:pojo>
<beanclass="test.TargetService">
<jsr181:pojo>
</jsr181:endpoint>
</beans>
HerewefirstwirebothEchoProxyServiceandTargetServiceasJSR181-compliantservicesontotheJBIbus.NextwedefineaJBIproxyfortheTargetService.Ifwecloselyobservetheproxyconfiguration,wecanseethatweareinsistingthattheproxytoimplementthetypetest.IEcho.Thatmakessenseandisnotasurprisesincethetargetserviceclass,test:TargetServiceisalsooftypetest.IEcho.
DeploymentConfigurationFordeployment,wewillpackagetherelevantartifactsfortheJSRproxybindingintoastandardSA.WewillalsohaveanHTTPboundSAsothatwecanuseasimpleHTTPclienttotestthesetup.Astheconfigurationsareexactlythesameaswhatweusedinthepreviousexample,theyarenotrepeatedhere.
DeployingandRunningtheSampleTobuildtheentirecodebaseanddeploythesample,changedirectorytoch13\JbiProxy\01_CompatibleInterfacewhich
containsatop-levelbuild.xmlfile.Executeantasshownhere:
cdch13\JbiProxy\01_CompatibleInterface
ant
Now,bringuptheServiceMixcontainerbyexecutingtheservicemix.xmlfilecontainedinthesamefolder.
cdch13\JbiProxy\01_CompatibleInterface
%SERVICEMIX_HOME%/bin/servicemixservicemix.xml
TheClient.htmlprovidedagaininthesamefoldercanbeusedtosendmessagestotestthedeployedservice.NowclickingSendontheclientwillroutetherequestmessagetotheServiceMixESB.AttheServiceMixconsole,youcanseethatEchoProxyService.echoisinvokedfirst,whichwillthendelegatethecalltoTargetService.echo.Thisisshowninthefollowingscreenshot:
JBIProxySampleimplementingInCompatibleinterfaceInthesecondsampleonJBIProxy,wewillmakeasimplebutsignificantchangeintheinterfacesimplemented.WewillcreateaJBIproxyimplementinganinterfaceincompatibletothetargetservice.Then,inplaceofthetargetservicewewillusetheproxyinstance.Thenanycallsintendedtothetargetservicewillbefirstroutedtotheproxyandtheproxyinturnwilldelegatethecalltothetargetservice.Thestructuralrelationshipbetweenvariousclassesparticipatingintheinteractionisshowninthefigure:
Intheabovefigure,youmighthavenoticedthateventhoughweusetwocompletelydifferenttypes(IEchoandITarget)astheinterfaces,themethodsdeclaredinthesetwointerfacesarethesameineveryrespect.Thisisahackwewanttointroduceintentionally.InotherwordsouraimhereistoinvokethemethodinTargetService.But,wewanttodoitthroughtheproxyonly.Wewanttheproxytobecreated
implementingadifferentinterface,IEcho.Hence,IEchoisdifferentfromtheITarget.ThismeansifwegobythenormalJavatypecompatibilityrules,theproxywhichwecreatedhereis"technicallyincompatible"withthetargetservice.Butaproxyisaproxyandhenceitcanproxycallseventoadifferenttype.However,Aswewanttoinvokethesamemethodintheproxytoo,wehavepurposefullykeptthemethodnamesameinboththeproxyinterfaceandthetargetserviceinterface.
ProxyCodeListingThecodebaseforthesampleislocatedinthefolderch13\JbiProxy\02_IncompatibleInterface\01_
JsrProxy\src.
ThisfoldercontainstheinterfaceIEchoandtheclassEchoProxyServiceimplementingtheIEchointerface.Now,wehaveonemoreinterfaceITargetandanotherclassTargetServiceimplementingtheITargetinterface.
Theseclassesareexplainedhere:
IEcho.java:Inthissamplealso,theIEchointerfacedeclaresasinglemethodechowhichtakesaStringparameterandreturnsaStringtoo.
publicinterfaceIEcho
{
publicStringecho(Stringinput);
}
EchoProxyService.java:HerealsotheEchoProxyServiceisa
convenientclasswhichwillactasmechanismforroutingrequeststotheJBIProxy.Moreover,EchoProxyServiceimplementstheaboveinterfaceIEcho.
publicclassEchoProxyServiceimplements
IEcho
{
privateIEchoecho;
publicvoidsetEcho(IEchoecho)
{
this.echo=echo;
}
publicStringecho(Stringinput)
{
System.out.println("EchoProxyService.echo.
this="+this);
returnecho.echo(input);
}
}
ITarget.java:Here,weintroduceanewinterfaceITarget,whichisincompatibletotheinterfaceIEcho.Butpurposefullywehaveretainedthemethodecho.
publicinterfaceITarget
{
Stringecho(Stringinput);
}
TargetService.java:Asperourdiscussionearlier,TargetServiceimplementsthenewinterfaceITarget,notIEcho.
publicclassTargetServiceimplementsITarget
{
publicStringecho(Stringinput)
{
System.out.println("TargetService.echo:
String.this="+this);
returninput;
}
}
XBean-basedJBIProxyBindingUsingXBean,wewillnowconfiguretheJBIproxytobedeployedontothestandardservicemix-jsr181JBIcomponent.Thexbean.xmlisasshownasfollows:
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:jsr181="http://servicemix.apache.org/jsr181/1.0"
xmlns:http="http://servicemix.apache.org/http/1.0"
xmlns:test="http://test">
<classpath>
<location>.</location>
</classpath>
<jsr181:endpointannotations="none"
service="test:echoService"
serviceInterface="test.IEcho">
<jsr181:pojo>
<beanclass="test.EchoProxyService">
<propertyname="echo">
<jsr181:proxyservice="test:TargetService"
context="#context"type="test.IEcho">
<property>
</bean>
</jsr181:pojo>
</jsr181:endpoint>
<jsr181:endpointannotations="none"
service="test:TargetService"
serviceInterface="test.ITarget">
<jsr181:pojo>
<beanclass="test.TargetService">
<jsr181:pojo>
</jsr181:endpoint>
</beans>
Observetheproxyconfigurationagain.Wecanseethatthistimeweareinsistingthattheproxyimplementsthetypetest.IEcho,eventhoughtheinterfacetypeforthetargetserviceistest.ITarget.Thisiswhataproxyisallabout.Inclearterms,theJBIherewillgenerateaproxyfortest.TargetService.Sotheproxy'sexposedinterfaceis,bydefault,complianttotest.ITarget.However,wewanttheproxytobecomplianttotest.IEchoalso,whichistheinterfacetheclientinitiallytargetedto.
DeploymentConfigurationFordeployment,wewillpackageagainalltherelevantartifactsfortheJSRproxybindingintoastandardSA.WewillalsohaveanHTTPboundSAsothatwecanuseasimpleHTTPclienttotestthesetup.Astheconfigurationsareexactlythesameaswhatweusedinpreviousexample,theyarenotrepeatedhere.
DeployingandRunningtheSampleTobuildtheentirecodebaseanddeploythesample,changedirectorytoch13\JbiProxy\02_IncompatibleInterface
whichcontainsatop-levelbuild.xmlfile.Executeantasshownhere:
cdch13\JbiProxy\02_IncompatibleInterface
ant
Now,bringuptheServiceMixcontainerbyexecutingtheservicemix.xmlfilecontainedinthesamefolder.
cdch13\JbiProxy\02_IncompatibleInterface
%SERVICEMIX_HOME%/bin/servicemixservicemix.xml
TheClient.htmlfileprovidedinthesamefoldercanbeusedtosendmessagestotestthedeployedservice.NowclickingSendontheclientwillroutetherequestmessagetotheServiceMixESB.AttheServiceMixconsoleyoucanseethatEchoProxyService.echoisinvokedfirstwhichwillthendelegatethecalltoTargetService.echo.Thisisshowninthefollowingscreenshot:
InvokeExternalWebServicefromtheServiceMixSampleYouhavenowseenhowtosetupaJBIproxyandhowtoinvokeaproxyjustlikeaPOJOboundtoJBI.NowyoucanextendthesameprinciplesifyouneedtocalloutfromaJSR181SUtoaHTTPproviderinordertointeractwithanexternalwebservice.YoucanuseXFiretocreatestubclassesbasedonyourWSDLexposedbyyourexternalwebservice.NowyoucaninjectthestubintoyourJSR181SU.ThestubwillbeusedbytheproxytogeneratetheexchangewiththeHTTPprovider(whichshouldbereferencedasthe"service").
YouhavealreadyseeninChapter10,howtobindawebserviceexternaltotheJBIontotheJBIbus.ThenanyJBIcomponentcanexchangemessageswiththeremotewebservice.Oneaspectwhichyouneedtonoteisthatwehavebeenexchangingmessagesinadocument-orientedfashion.HoweverusingJBIproxynow,itispossibletoinvokewebservicesintheRPCstylefromwithintheJBIbus.ForthisweleveragethestubclassesgeneratedoutfromthewebserviceWSDLusingAxis.
WebServiceCodeListingWeareinterestedinproxysetuptoaccessaremotewebservice,hencewewillnotdiscussthedetailsofthewebservicedeploymentinthissection.Instead,wewilljustbrowsethroughtheimportantwebserviceinterfacesandthe
associatedWSDLandthenmoveontobindingtheproxy.
ThewebserviceimplementstheIHelloWebremoteinterfacewhichinturnextendstheIHellobusinessinterface.Theyarelistedhereasfollows:
IHello.java:IHelloisasimpleBI,havingasinglebusinessmethodhello.
publicinterfaceIHello
{
Stringhello(Stringparam);
}
IHelloWeb.java:Inordertodeployawebservice,weneedaninterfacecomplyingwiththeJavaRMIsemantics,andIHelloWebwillservethispurpose.
publicinterfaceIHelloWebextendsIHello,
java.rmi.Remote{}
HelloWebService.wsdl:
ThemainsectionsinthewebserviceWSDLisshownasfollows:
<?xmlversion="1.0"encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="http://AxisEndToEnd.
axis.apache.binildas.com"...>
<wsdl:types...>
<wsdl:message...>
<wsdl:portTypename="IHelloWeb">
</wsdl:portType>
<wsdl:binding
name="HelloWebServiceSoapBinding"
type="impl:IHelloWeb">
</wsdl:binding>
<wsdl:servicename="IHelloWebService">
<wsdl:port
binding="impl:HelloWebServiceSoapBinding"
name="HelloWebService">
<wsdlsoap:address
location="http://localhost:8080/AxisEndToEnd/services/
HelloWebService">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
Thisisenoughaboutthewebserviceandwewillmoveontothenextstep.
AxisGeneratedClientStubsWeuseorg.apache.axis.wsdl.WSDL2Javaclassinthewsdl2javatasktogenerateclient-sidebindingclassesandstubs.Themainclassesareavailableinthefolderch13\JbiProxy\03_AccessExternalWebService\
01_ws\gensrcandtheyareasfollows:
HelloWebService.java
HelloWebServiceSoapBindingStub.java
IHelloWeb.java
IHelloWebService.java
IHelloWebServiceLocator.java
AlltheaboveartifactsareAxisgeneratedclient-sidestubs,hencewewillnotlookintothedetailsofthemhere.Instead,letuslookintothestructuralrelationshipbetweenthevariousdevelopercreatedandAxisgeneratedartifactsshowninthe
followingfigure:
Referringtotheabovediagram,letusunderstandtherelevantartifacts.Similartothesamplespreviouslylistedinthischapter,hereouraimistogenerateaJBIproxyforan
externallyboundwebservice.Wearedoingthisusingthefollowingclasses:
ITarget.java:ThisinterfaceissynonymoustotheBIIHello,havingasinglebusinessmethodhello.Wewanttoauto-routerequest-responsethroughtheJBIproxy.Inordertofacilitatethiswehaveretainedthemethodsignatureintheinterfacesthesame.
publicinterfaceITarget
{
Stringhello(Stringinput);
}
TargetService.java:InTargetService,weauto-wirethewebservicestub.So,thehelloWebinstancefieldinTargetServicewillholdareferencetothestubtothewebservice.WhenthehellomethodisinvokedinTargetService,thecallisdelegatedtothestubwhichwillinvoketheremotewebservice.
publicclassTargetServiceimplementsITarget
{
private
com.binildas.apache.axis.AxisEndToEnd.
IHelloWebhelloWeb;
publicTargetService(){}
public
TargetService(com.binildas.apache.axis.
AxisEndToEnd.IHelloWebhelloWeb)
{
this.helloWeb=helloWeb;
}
publicStringhello(Stringinput)
{
System.out.println("TargetService.echo:
String.this="+this);
try
{
returnhelloWeb.hello(input);
}
catch(Exceptionexception)
catch(Exceptionexception)
{
exception.printStackTrace();
returnexception.getMessage();
}
}
}
IHelloProxy.java:WenowneedtowiretheJBIproxytothewebservicesstub.IHelloProxyisaninterfacedefinedforthispurposeandhenceishavingthesamesinglebusinessmethod,hello.
publicinterfaceIHelloProxy
{
publicStringhello(Stringinput);
}
IHelloProxyService.java:HelloProxyServiceisawrapperoradapterfortheJBIproxy.Inotherwords,thehelloProxyinstancefieldinHelloProxyServicewillrefertotheJBIproxy.
publicclassHelloProxyServiceimplements
IHelloProxy
{
privateIHelloProxyhelloProxy;
publicvoidsetHelloProxy(IHelloProxy
helloProxy)
{
this.helloProxy=helloProxy;
}
publicStringhello(Stringinput)
{
System.out.println("HelloProxyService.hello.
this="+this);
returnhelloProxy.hello(input);
}
}
ThebeanwiringdiscussedinthissectionisdoneusingSpringandisshowninthenextsection.
XBean-basedJBIProxyBindingUsingXBean,wewillnowconfiguretheJBIproxytobedeployedontothestandardservicemix-jsr181JBIcomponent.
Thexbean.xmlisasshowninthefollowingcode:
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:jsr181="http://servicemix.apache.org/jsr181/1.0"
xmlns:http="http://servicemix.apache.org/http/1.0"
xmlns:test="http://test">
<classpath>
<location>.</location>
</classpath>
<jsr181:endpointannotations="none"
service="test:echoService"
serviceInterface="test.IHelloProxy">
<jsr181:pojo>
<beanclass="test.HelloProxyService">
<propertyname="helloProxy">
<jsr181:proxyservice="test:TargetService"
context="#context"type="test.IHelloProxy">
<property>
</bean>
</jsr181:pojo>
</jsr181:endpoint>
<jsr181:endpointannotations="none"
service="test:TargetService"
serviceInterface="test.ITarget">
<jsr181:pojo>
<beanclass="test.TargetService">
<constructor-argtype="com.binildas.apache.axis.
AxisEndToEnd.IHelloWeb">
<refbean="stub">
<constructor-arg>
</bean>
</jsr181:pojo>
</jsr181:endpoint>
<beanid="stub"
class="com.binildas.apache.axis.AxisEndToEnd.
HelloWebServiceSoapBindingStub">
<constructor-argtype="java.net.URL"index="0">
<refbean="url">
<constructor-arg>
<constructor-argtype="javax.xml.rpc.Service"
index="1">
<refbean="serviceLocator">
<constructor-arg>
</bean>
<beanid="url"class="java.net.URL">
<constructor-arg>
<value>http://localhost:8080/AxisEndToEnd/
services/HelloWebService</value>
</constructor-arg>
</bean>
<beanid="serviceLocator"
class="com.binildas.apache.axis.AxisEndToEnd.
IHelloWebServiceLocator">
</bean>
</beans>
Wenowhaveenoughconfigurationstoinvoketheexternalwebservice.Isthereanythingfishyintheconfigurationabove?YoucangothroughthatonceagainandletmewaittilltheendofourdiscussiontoexplainwhatIamhidingfromyouatthispoint.
DeploymentConfigurationFordeployment,wewillpackageagainalltherelevantartifactsfortheJSRproxybindingintoastandardSA.WewillalsohaveanHTTPboundSAsothatwecanuseasimpleHTTPclienttotestthesetup.Astheconfigurationsareexactlythesameaswhatweusedinthepreviousexample,theyarenotrepeatedhere.Butweneedtomentiononethinghere.TheJBIproxyuseswebservicestubclassestoinvoketheexternalserviceandhencedependsontheAxislibraries.WeresolvethisdependencybycompilingthestubclassesandincludingthemalsointheSA.WealsocopyallrelevantAxisAPIjarstotheServiceMixoptionallibrarypath.Theanttargetforthatisgivenhere:
<targetname="copy-dependency"depends="init">
<javacsrcdir="../01_ws/gensrc"
destdir="${build.dir}">
<classpathrefid="javac.classpath"/>
<includename="**/*ServiceLocator.java">
<javac>
<copytodir="${servicemix.home}/lib/optional"
overwrite="true">
<filesetdir="${axis.home}/lib"includes="*.jar"
>
<copy>
</target>
DeployingandRunningtheSampleTobuildtheentirecodebaseanddeploythesample,changedirectoryto
ch13\JbiProxy\03_AccessExternalWebService
whichcontainsatop-levelbuild.xmlfile.Executeantasshownhere:
cdch13\JbiProxy\03_AccessExternalWebService
ant
Thiswillbuildthewebservice,generaterequiredwebserviceclientstubs,andalsopackageallthenecessaryserviceassemblies.First,weneedtodeploythewebservice.Forthat,transferthewebservicewarfileplacedinch13\JbiProxy\03_AccessExternalWebService\
01_ws\distfolderintothewebappsfolderofyourfavoritewebcontainerandrestartthecontainer.Youcandoublecheckwhetheryourwebservicedeploymentworksbyexecutingaclientkeptinthewebservicefolderitself.Forthat,executetheantruntargetasfollows:
ch13\JbiProxy\03_AccessExternalWebService\01_ws
antrun
Now,bringuptheServiceMixcontainerbyexecutingtheservicemix.xmlfilecontainedinthesamefolder.
ch13\JbiProxy\03_AccessExternalWebService
%SERVICEMIX_HOME%/bin/servicemixservicemix.xml
TheClient.htmlprovidedagaininthesamefoldercanbeusedtosendmessagestotestthedeployedservice.
ProxyandWSDLGenerationIhaveaskedyoutogothroughtheJBIproxyXBeanconfigurationoncemoreinaprevioussection.Doyouthinkwehaveactuallymadethewebserviceaproxy?Ifweneedtotrulyproxythewebservice,thentheXBeanconfigurationshouldbesomethinglikethefollowingcode:
<jsr181:endpointannotations="none"
service="test:TargetService"
serviceInterface="com.binildas.apache.axis.
AxisEndToEnd.IHelloWeb">
<jsr181:pojo>
<bean
class="com.binildas.apache.axis.AxisEndToEnd.
HelloWebServiceSoapBindingStub">
<constructor-argtype="java.net.URL"index="0">
<refbean="url">
<constructor-arg>
<constructor-argtype="javax.xml.rpc.Service"
index="1">
<refbean="serviceLocator">
<constructor-arg>
</bean>
</jsr181:pojo>
</jsr181:endpoint>
Theaboveconfigurationisrightandthatiswhatweneedtoproxythewebservice.HowevertheissuehereisthattheclassHelloWebServiceSoapBindingStub,whichifyoulookatthesourcecodeyoucansee,isdependentonmanyapacheaxisRPCAPIclasses.ForproperJBIproxying,theJBIcontainershouldbeabletogenerateWSDLoutoftheexposedAPIbutitmaynotmakesensetogenerateWSDLout
oftheseRPC-dependentclasses.InfacttheWSDLgeneratorfailsandthrowsanerror.HenceinsteadwhatwehavedoneinthepreviousexampleisthatwehaveaproxywrapperTargetServicetowhichweinjecttheHelloWebServiceSoapBindingStubinstanceusingtheSpringinjectionmechanism.ThenwedelegateanycallsfromtheTargetServiceinstancetothestubinstances,andthatdoesthemagic.
SummaryProxiesarestrongfeaturesintheJavalanguagepackage,andsimilarfunctionalitycanbeavailedfromwithinyourJBIESBusingJBIproxies.Interceptionandre-routingaresomeofthefeatureswecanimplementusingproxies.YouhavealsoseenhowanexternalwebservicecanbeboundtotheJBIbusandthenexposedasproxieswithinthebusitselfsothatothercomponentswithinthebuscanroutemessagesthroughtheseproxies.Thebuildingblocksdemonstratedinthischaptercanbeusedtosolveyourintegrationproblems.
Wewilllookintoamoreinterestingconcernintheservicesnetwork—versioningofservices,inthenextchapter.
Chapter14.WebServiceVersioningVersioningservice,especiallyofthewebservices,isatopicofheateddiscussionsinmanyoftheforumsandsites.Eventhoughtherearemanyapproachestothistopic,wecannotoftenfindanyconcreteguidelineorcodeshowingtheimplementation.Thisisbecausethetopicisnotsimple.Theterm"Versioning"meansdifferentthingstodifferentpeople,dependinguponthecontextinwhichtheyarespeaking.Forsome,versioningmeansawaytomanagecompatiblechangeintheserviceimplementationalone,withoutanymajorchangeintheservicedescription.However,forthosewhodefineservicesforalargecorporateenterprise,versioningisamechanismortoolwithoutwhichhecannotcontroltheeverincreasingcomplexityofanSOAecosystem.
TheeffectiveuseofanESBinfrastructureprovidesameanstosolvetheversioningproblemsandinthischapterwearegoingtolookattheworkingcodeinactiondemonstratinghowwecanversionthewebservices.
Wewilllookintothefollowingtopicsinparticular:
Thewhatandwhyofserviceversioning
VersioninginanSOAcontext—whatisrequired
Differentstrategiesinversioningthewebservices
Approachesinversioningthewebservices
Aserviceversioningsample—workingcodeinESB
ServiceVersioning—AMeanstoSOAVersioningisimportant,whetherwearedealingwithbinaryprogrammingparadigmssuchastheGlobalAssemblyCache(GAC)of.NETruntimeorwearedealingwithSOAinfrastructuressuchastheESB.HoweverwhenitcomestoSOA,versioningwillhaveaslightlydifferentmeaningwhichIwilltrytodescribeinthissection.
ServicesareAutonomousSOAisnowthebuzzword—peopleuseitineveryothercontext;everyonehastheirownbeliefsandunderstanding.Whateveritis,autonomybecomestheprimeconcerninanSOAimplementation.First,letusaskourselveswhywemovedawayfromouroldCORBAorourwell-knownJavaRMIarchitecturesforserviceimplementationandconsumption.LeavingasideallthevarieddefinitionsofSOAandthemanyadvantagesanSOAyields,autonomyisoneofthebestfeaturesSOAbringstothetableofboththeprovidersandconsumers.Serviceproviderscankeeponchangingtheirserviceimplementations,eithertoaddanewfunctionalityortoextendorenhancetheexistingfunctionality.Indoingso,serviceconsumersshouldbeunaffected;thatis,theyshouldn't
evenbeawarethatsomethinghaschanged.Needlesstosaythattheservicesdescriptionshouldn'tchange,noteventheserviceURLshouldchange.
ChangeistheOnlyConstantThingIfeverythingremainsstatic,itisanidealworldforanengineer,eventhoughanartistwouldthencursetheworld.However,timehasshownthattheonlyconstantthingintheworldischange.Networkschange,platformsandframeworkschange,operatingsystemschangeinversionsandsupportability,andserviceimplementationsalsochange.
AchangemaybetoenhancetheQOS,perhapstoimprovetheresponsetimebyintroducinganewalgorithminthecode.Changecanalsoaddanewfunctionalitytotheexistingserviceendpoints.Suchchangesareusuallymanageablebynotrevealingthechangetotheexternalworld,especiallytotheserviceconsumer.Sometimes,wemayalsoneedtointroduceorcutshortaparametertothealreadyexistingservicemethod.Insuchacasetheexistingconsumersmayhavetodosomechangesattheirendalso,tomakethestubscompatibletotheserver-sidechanges.Infactmanytimes,theserviceconsumershavetorebuildandrecompiletheirclient-sidestubsandadjusttheircallingcodetomakethemcomplywiththeremoteinterface.ForsmalldeploymentsthesecanbedonebydeveloperswiththebestdesignandcodepracticesandwiththehelpofIDEsandtools.However,thiswillturnouttobeanightmarewhenthenumberofserviceskeepsonincreasing,whichistypicalofeverygrowingenterprise.
AllPurposeInterfacesThereisalsothenotionofagenericorwholepurposeserviceinterface.Asampleisshowninthefollowingcode:
publicStringserviceMethod(StringserviceXml);
Theaboveinterfacetalksaboutagenericservice(eventhemethodnameisgeneric,"serviceMethod"),whichtakesagenericparameterandreturnsagainagenericvalue.PassingtheXMLinadocumentstyletoagenericmethodinterfaceliketheoneshownaboveisanexample.Here,wheneverachangeisrequiredweneedn'treflectthatintheinterface-level,buteverychangeishiddeninthestringformattedrequestandresponsemessages.Atfirstsightthismightseemtobeasolutiontothechangeproblem,butexperiencehasshownthatthisisinfactananti-patternintheSOAworld.Weloseallstatictypebindingwhichmeanseventhetoolswillnotfindoutanymismatchortypevalidationerrors.Thiswillberevealedonlyaftertheserviceinvocationasareactiveerrorscenario.
SOAVersioning—Don'tTouchtheAnti-PatternLetusconsideratypicalwebservicemethodsuchasthefollowing:
publicStringtransferFund(StringfromAccount,
StringtoAccount,doubleamount);
StringtoAccount,doubleamount);
Here,themethodwilltransferthefundfromoneaccounttoanother.Letusassumethatonefinedaywewanttochangetheservicetoacceptonemoreextraparameter,liketheoneshowninthefollowingcode:
PublicStringtransferFund(StringfromAccount,
StringtoAccount,doubleamount,String
transactionPassword);
Now,hereareasetofquestionsforthereader.Wemayormaynotanswerallthesequestionsbutatleastagreethatweidentifythepossiblecaveatstoourtraditionalthinking!Thefollowingarethequestionsforthereaderstothinkover.
1. Doweneedtoversionservicesoroperations?
ThefirstquestioninSOAiswhethertransferFundisaserviceoranoperation.WeneedtoappreciatethatawebserviceisdescribedbyaWSDLandaWSDLcancontainmultipleoperationsdefinedintheportType.Ifso,whentransferFundneedstoincludeonemoreparameterintherequest,hastheversionoftheoperationchangedortheversionoftheservicechanged?
2. Canweoverloadaservice?
Ifweconsiderobject-orientedprogramming,thesameclasscanincludeboth"versions"ofthetransferFundmethod—wecallitmethodoverloading.Fortunatelyorunfortunately,WSDLdoesn'tallowmethodoverloading.Nowweareleftwithfewotherstrategies(orhacks?)tocombatthechange,whichisdescribedinthenextpoint.
3. Newversionornewservice?
Tohandlethenewextraparameter,IcancreatethetransferFund02methodwhichwilltakeanextraparameterorrenametheservicenametosomethingdifferentliketransferFundSecurely.Whateverour
strategy,thequestionhereishavewecreatedanewversionoftheserviceoranentirelynewservice?
4. Willourinformationmodelsaveusfromschemachanges?
Letusconsideranewservice:
publicAddressgetAddress(CustomerInfo
customerInfo);
TheaboveservicewillreturnbackanAddressifyouprovidetheCustomerInfoofthecustomerwhoseAddresshastoberetrieved.Now,letuslookintoAddress.
publicclassAddress{
privateStringhouseNumber;
privateStringstreet;
privateStringcity;
}
Now,wechangetheAddresstoincludeanadditionalfieldtoalsotakecareofthezipcodeasshownhere:
publicclassAddress{
privateStringhouseNumber;
privateStringstreet;
privateStringcity;
privateStringzip;
}
DoyouthinkthischangehasintroducedanychangetothegetAddressservice?Apparentlynot,sincetheservicedefinitionremainsthesame,butinfactIhavealteredmydatatypewhichinturnwillmaketheexistingconsumercodebaseincompatiblewiththenewservice.
Sofarsogood,nowthefinalquestion—forscenariosthatwehaveseenabove,shouldwecreateanewversionoftheexistingserviceorshouldwedefineanewserviceitselfbynot
disturbingtheexistingone?
Ratherletusrestatetheabovepointsinthismanner—inSOA,servicesshouldn'tmutatefromversiontoversion.Thiswillsafeguardanyexistingconsumers.However,newservicescanbeintroducedwhichisnottoocomplicatedbecausenewserviceswillhavetheirownseparateendpoints.Moreover,irrespectiveofwhethertheconsumersareneworexisting,theywillusethenewendpointtoavailthenewservice.Atthesametimeservicescanalsobeenhancedorupgraded.AnenhancementcaninvolveincreasingtheQOSfeaturesoftheserviceorbringinginnewimplementationtechnologiesbehindthescenes,keepingtheserviceinterfaceuntouched.Whenyouupgradeaservice,youcannowdecidewhattodowiththe"oldversion"ofthesameservice.Ipurposelyusedthewords"oldversion"thistimebecauseversioningofservicesmakessenseinthecontextofenhancingorupgradingservicesonly,notinthecontextofintroducingnewservices.
TypescanInherit—WhynotMySchemasAgaininOOP,youcandefineabasetype(likeAnimal)andderivemultipletypes(likeCatandDog)fromthat.Thederivedclassesarealwaystypecompatibletothebasetype(YoucanalwayssubstituteanAnimalwithaCatoraDog).
W3CXMLschema's<extension>providesusameanstoextendXMLschemas.Howcanthisbeofanyusetoourwebservice?CanwesubstituteanAddressXMLinstancewhich
containsazipcodeelementinplaceofwhereaserviceexpectsanAddresswithoutthezipcode?Whethertheservicewillstillworkornotdependsonwhatextrahooksyouattachtoyourwebservicesinfrastructuretobridgetheschemamismatch.Hence,weacknowledgethefactthatschemasareextensibleandarealsoabletoversion.Butthatmightnotstraightawaymaptotheconceptofextendingversioningprinciplestoservices.
IfNotVersions,ThenWhatHavingdiscussedenoughaboutversioningaroundservices,letusnowlookintowhatisneededinanSOA.Weallagreethatmultipleflavor(variants)ofservicecanexistandifallofthemcoexist,weneedagoodgovernancemechanismalsotosatisfyconsumerrequestsaspertheagreeduponSLA.ThisiswhereanESB-basedroutingmechanismwilladdvalue.Theword"version"isverycommontothesoftwaredevelopersandso,wepreferstoretainthatwordinthediscussionsalso—topointtomultiplevariantsoftheservice.Letusnowlookintoversioningofservicesinthiscontext.
StrategytoVersionWebServiceGiventheproblemofchange,thenextthingistofindouttheexactmechanismtofollowtoversioncontroltheservices.Infact,wehavealreadyseenoneway,whichisthegenericstring
formattedmessagesapproach,butasdiscussed,thismaynotbethebestavailablemethod.Wewillnowlookintomultipleoptionsavailableforserviceversioning.
WhichLeveltoVersionOneimportantquestiontoanswerinserviceversioningisthelevelatwhichwehavetoversioncontrol.Bylevelwemeanwhetheratthewholeserviceinterface-levelorattheindividualservicemethod-level.PerhapsthisquestionisoutofcontextbecausewhenwespeakonSOAanditsconstituentservices,wealwaysmeansserviceswhicharecoarsegrained,whichareneverindividualfinegrainedmethodinvocations.Inotherwords,wealwaysspeakabout"transferfund","authorizecredit",or"validateservice"requestinSOA,butnotfinegrainedmethodssuchas"updatebalancecellinaccounttable".Thisfollowsthatservicescanbeversionedasawhole.Forexample,inafundtransferservicewecaneitherversioncontrolfortheservicefundtransferorfortheindividual,composedservicessuchaswithdrawalanddeposit.Toversioncontrolasawhole,weneedtoversionthefundtransferservice,notthecomposedfinegrainedmethods.
VersionControlinaSchemaAnXMLschemaisusedinawebservicedescriptiontodefinethemessageparametersexchangedbetweentheconsumersandproviders.TheXMLschemaalsodefinesanamespacewhichdifferentiatesoneschemafromanother.Moreover,a
schemaalsoprovidesamechanismforextensibility.Thus,aXMLschemaisadoubleedgedsword.Ononeside,itgivestheflexibilityofextensionandontheothersideitgivesamechanismtoconstraintorseparateoutbetweenextensions.Letuslookintoasampleschemaandexplainthis.
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.product.org">
<xs:complexTypename="employee">
<xs:sequence>
<xs:elementname="firstName"type="xs:string">
<xs:elementname="lastName"type="xs:string">
<xs:anynamespace="##any"processContents="lax"
minOccurs="0"maxOccurs="unbounded">
<xs:sequence>
</xs:complexType>
<xs:schema>
TheaboveisanextensibleXMLschema.ThefirstNameandlastNameelementsareboundwhereasitprovidesanextensionmechanismtoaddadditionalconstructsafterthelastName(forexample,BinilDasMr,CraigMaretPhD,andsoon)whilestillremainingvalidbasedontheoverallschemadefinition.Atthesametime,thetargetNamespacemechanismalsohelpsustoseparateoutdifferentschemas,andthustodifferentiatebetweenschemaconstrainedXMLdata.
targetNamespaceforWSDL
AWSDLdocumentisthedescriptionofawebserviceandhasadefinitionselementthatcontainsthetypes,message,portType,binding,andserviceelements.
Forthedefinitionselement,targetNamespaceisthenamespaceforinformationaboutthereferredservice.OneWSDLdocumentcanimportotherWSDLdocuments,andsettingtargetNamespacetoauniquevalueensuresthatthenamespacesdonotclash.ThedefaultnamespaceoftheWSDLdocumentisxmlns,anditissettohttp://schemas.xmlsoap.org/wsdl/.AlltheWSDLelements,suchasdefinitions,typesandmessagesresideinthisnamespace.xmlns:xsdandxmlns:soaparethestandardnamespacedefinitionsusedforspecifyingSOAP-specificinformationaswellasdatatypes.xmlns:tnsstandsforthisnamespace.
TheWSDLsaregeneratedoutoftheserviceinterfaces.TheseinterfacesmaybeinJavaor.NET.WhentoolsgeneratetheWSDL,theywillhavetheirdefaultstrategyonwhatvaluetoputforthetargetNamespaceattribute.Manyatimes,thiscanbeoverriddenbythetools.ApacheAxisWSDL2JavaandJava2WSDLdothis.Hence,targetNamespaceisanattributewhichwecancontrolifrequired.ThetargetNamespacecanbegivenvaluesinmultipleformats,dependinguponwhichwaywewanttocontrol.Examplesaregivenhere:
targetNamespace=http://www.binildas.com/types/products/v1/1
targetNamespace=http://www.binildas.com/2006/12/30/products
Thisalsoprovidesanexcellentmechanismtoversioncontrolservicesandwewilldemonstratethisinexampleslaterinthischapter.
VersionParameterIncludingaversionparameterisanothermethod.Thisspecialparameterisusuallypassedthroughtheheadersofthewebservicerequest.Itisalsopossibletoincludethisparameterinthemessagepayload(orbodycontent).Ineitherform,inordertomakethismechanismworkweneedtopassthevaluefortheversionparameteralongwitheveryrequest.AsampleSOAPrequestwithaversionparameterintheheaderisshowninthefollowingcode:
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
<soap:Header>
<Version
xmlns="http://product.services/binildas.com">
</Version>
</soap:Header>
<soap:Body>
....
</soap:Body>
</soap:Envelope>
Asdiscussedbefore,thesamecanbeincludedinthebodyasshowninthefollowingcode:
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
<soap:Header>
</soap:Header>
<soap:Body>
<svc:hello
xmlns:svc="http://product.services/binildas.com">
<Version
xmlns="http://product.services/binildas.com">
</Version>
....
</svc:hello>
</soap:Body>
</soap:Envelope>
WebServiceVersioningApproachesWehaveseenafewstrategiesofwebserviceversioning.Letusnowlookatsomeapproachesofimplementingthoseversioningstrategies.
CovenantAcovenantisanif-then-elsewayofversioningapproach.Thiscanbedoneusingmultiplestrategieswhichwesawearlier.Inanystrategy,thecovenantapproachlooksforsomeifs,anddependingupontheoutcomeoftheconditionasuitablethenclausewillbeexecuted.Itcanalsohaveanelseoradefaultclause.Hencethisapproachisusuallycombinedwitha
versioningflagandthisflagcanbeeitherintheformofaversionparameterorintheformofaversionsensitivevalueinthetargetNamespace.Thisisshowninthefollowingfigure:
AcovenantisusuallyexposedinaSingleEndpointAddress.Hence,allConsumerswillsendmessagestothesameaddress.DependinguponwhichversionoftheservicecontracttheConsumerisusingasuitableversionflagwillbepassedeitherasaversionparameterorthroughthetargetNamespace.Thecovenantusuallyimplementsacontent-basedrouter.Acontent-basedrouterisusedtorouteeachmessagetothecorrectrecipientbasedonthemessagecontent.TheroutingcanbebasedonanumberofcriteriasuchastheexistenceofaversionparameterandtheversioninfointargetNamespace,.TheadvantageofthecovenantapproachisthatConsumersareunawarethatmultipleserviceversionscoexistattheProvider'send.Hencetheyneedn'tadjusttheiraddresstoroutetospecificserviceversions.Instead,theywillplacetheirversionflaginthemessageandsendittothesameaddress.Itisuptothecovenanttoredirectthemessagetotheappropriateversionoftheservice.
MultipleEndpointAddressesIntheMultipleEndpointAddressapproach,eachversionofthewebserviceisallottedaseparateendpointaddress,andtheyarethenboundtoalookupmechanismlikearegistry.Now,theConsumerhastodecidetheendpointaddressforserviceinvocationbylookingattheServiceRegistry,andcrossmatchingtheversionofinterest.ThentheConsumersendsmessagestotheselectedendpointaddressofinterest.ThischannelwillroutetheMessagestraighttotheexactversionoftheservice.Theschemaisshowninthefollowingfigure:
WebServiceVersioningSampleusingESBWediscussedthetheoryofwebserviceversioning,nowitistimetoputthatincode.Letusdothatwiththehelpofasampleusecase.Onethingtobenotedhereisthatto
implementthesamplewemakeuseofEIPsbuildingblockswhicharedescribedindetailinachapteroftheirown.
SampleUseCaseThesampleusecaseisaboutsettinguptheJBIcomponentstoeffectivelyenabletheversioningmechanismintheservices.AllthesecomponentsareconfiguredintheESB.AnexternalclientinteractswiththeESBthustestingtheversioningmechanism.TheESBisboundtothedifferentversionsofservices,whicharedefinedexternalandremotetotheESB.TheESBwillapplytheversioningrulesandroutetherequeststotherespectiveversionoftheservice.Thesampleusecaseisillustratedhereinthefollowingfigure:
Infactthissampleisnotascomplicatedasthefiguremakeitlook.Wewillseetheindividualcomponentsfirstandunderstandtheflow.
JMSclient:Inthissample,weusetheJMSchanneltosendwebservicerequests.TheJMSClientreadstheSOAPrequestmessagefromafileandsendsthemessagetotheJMSConsumerqueueconfiguredintheESB.One
pointtobenotedhereisthatwearegoingtousethetargetNamespacemechanismoftheWSDLtoimplementtheserviceversioning.IfweopentheSOAPrequest,wecanseehowwehavedesignedtheSOAPrequestsoastoincludeaversionspecificvalueforthenamespaceattribute.ThevaluecorrespondstothetargetNamespaceattributeofWSDLfortheSOAPrequest.
JMSconsumer:TheJMSConsumerisaservicemix-jmscomponentwhichallowsyoutosendJMSmessagestotheconfiguredqueue.Aconsumerrolefortheservicemix-jmscomponentimpliesthecomponentisaconsumertotheNMR.AnymessagescomingtothequeuewillbetransferredtothetargetServiceattributefortheJMSConsumer.
WhiteSpacetransformer:AvalidSOAPrequestcancomeinseveralforms,allinasinglelonglineorseparatedoutintomultiplelines,formattedwithindentationsandspaces.TomakethecontentreadyforanXPathquerymatchlaterintheflow,weusetheextraneousWhiteSpaceTransformercomponentwhichwilltrimoutallextraneouswhitespacesfromtheSOAPrequestpayloadandnormalizeitintoasingleline.
Content-basedrouter:TheContentBasedRouterisusedforallkindsofcontent-basedrouting.WeearlierdiscussedthatwehavedesignedtheSOAPrequestsoastoincludeaversionspecificvalueinthetargetNamespaceattributefortheSOAPrequest.HencenowwewilluseaContentBasedRouterwhichisaservicemix-eipcomponent.ThiscomponentwillinspectthevalueforthenamespaceattributecorrespondingtothetargetNamespaceattributeoftheWSDLembeddedintheSOAPrequestandseethematchingruleconfiguredatthecomponent-level.Dependinguponthematch,theContentBasedRouterwillroutetheSOAPrequestmessagetoanyoneofthesetofTransformerPipelinesconfigured.
Transformerpipeline:ThepipelineisastandardEIPcomponentandhenceisavailablereadilyasastandardJBIEIPcomponentinServiceMix.ThepipelinecomponentisanintegrationbridgebetweenanIn-Only(orRobust-In-Only)MEPandanIn-OutMEP.ByreceivinganIn-OnlyMEPbythepipeline,itwillsendtheinputmessageinanIn-OutMEPtothetransformerdestinationandtheninturnforwardtheresponseinanIn-OnlyMEPtothetargetdestination.Asperthat,ouraimhereistosendthemessagetoanIn-OutMEPcomponent(acontentretrieverinourcase)andthentoroutetheoutmessagefromthatcomponenttothenextchainintheflow(whichagaininourcaseisasecondpipeline).
Contentretriever:ThefunctionalityofthiscomponentistoextractthepayloadpartfromtheincomingSOAPrequest.Hence,wetrimouttheSOAPenvelopeandbodytags,andextractonlythecontentswithinthebodyelementtobesenttothenextcomponent.WesaidthatweneedtoinvokeawebserviceandyoumightwonderwhywewanttoextractthepayloadaloneratherthansendingthewholeSOAPrequesttothetargetwebservice.ThereasonwhywearedoingthiswillbeevidentwhenwereviewtheHTTPProvider.ContentRetrieverwillsendtheoutpartofthemessagebacktothetransformerpipeline.TheTransformerPipelinewillroutethismessagetothenextcomponentinthechain,whichistheServicePipeline.
Servicepipeline:OuraimhereistosendtheinputmessageinanIn-OutMEPtothenextcomponentwhichistheHTTPProvider.TheninturnforwardtheresponseinanIn-OnlyMEPtothetargetdestination,whichistheoutputJMSqueue.
HTTPprovider:AHTTPProviderroleimpliesthattheNMRistheconsumertothecomponent.Hence,theHTTPProviderislinkedwiththeRemoteWebServicesothatanyrequestcomingtotheHTTPProvidercanberoutedtothewebservice.WhentheHTTPProvidersendsarequesttothewebservice,itneedstospecifyaSOAPactionintherequestheader.Tofacilitatethiswehavetwoattributesnamely,soapandsoapActionattheHTTPProvider-level.AtruevalueforsoapattributesissupposedtowrapthemessagebodyinaSOAPenvelopewhereasthevalueforsoapActionwillbeembeddedastheSOAPactionintherequestheader.Forsomereason,ifwespecifythesoapActionattributealone,servicemix-httpdoesnotforwardtheSOAPactionheader.HencewearespecifyingsoapandsoapActiontogether.However,soapwillwraptherequestintheSOAPenvelope.Wedon'twantthebodycontentwrappedintwolevelsofSOAPenvelope.ThatiswhyintheContentRetrievercomponent(wealreadyhaveseenthisshortwhileago)weextractonlythecontentswithinthebodyelementtobesendtothenextcomponent.
Remotewebservice:Thisisanormalwebservicewhichcanbedeployedinanywebcontainerinfrastructure.
JMSprovider:TheSOAPresponseisplacedbackinthequeueconfiguredintheJMSProvidercomponentfromwheretheclientprogrampicksupthemessage.
HTTPconsumer:TheHTTPConsumercomponentsconfiguredherearejusttohelpyoutosendarbitrarymessagestothesamplesetupforanyad-hoctesting.
Wehavenowseenthemajorcomponentsconfiguredforthesampleapplicationandhowthemessageflowsthroughthem.Wealsohaveafewmoresettingssothatwecanactuallydemonstratethatwecancontrolmultipleversionsofwebservicestobeexposedtoclientsinthecovenant-basedsettings.Letuslookthatnow.
Infact,wehavetwoSOAPrequests,eachhavingtwodifferentvaluesforthetargetNamespaceattribute.WealsohavetwoJMSclientprogramssothatthereaderscaneasilytestthesetwoSOAPrequestsontheESB.TomakesuretherequestsareroutedseparatelytodifferentwebservicesbasedonthevalueoftargetNamespaceattribute,wealsohavetwowebserviceshostedandboundtotheESBinfrastructure.
Nowwewillmoveontothedetailsoftheconfigurationandothersettingsforthedemonstration.Forthat,alsohavealookatthefilesandfolderstructureorganizationwehavesothatwecanhostandmanagetwoversionsofwebserviceinthedemosetup.
Thefigureshowsonlythefilesrequiredforthedemosetup.Thetop-levelbuildiscapableofcallingthebuildfilesinthechildprojectfoldersandthuscanbuildtheentiredemoinasinglego.Thiswillthencreatemanyintermediateandfinalfoldersandartifactswhicharenotshownhere.
ConfigureComponentsinESBInthesampleusecasesectionyouhaveseenthevariouscomponentsusedforthedemo,andyouhavealsoseentheflowofmessage.LetusfollowthesameorderforcomponentsandseehowtheyareconfiguredinServiceMixsothatyoucaneasilycorrelatetotheflowweexplainedearlier.
JMSclient:TherearetwoversionsoftheJMSclients.Theyare:
ch14\WebServiceVersioning\JMSClient20061231.java
ch14\WebServiceVersioning\JMSClient20070101.java
BoththeseclientprogramsaresimilarexceptthefactthatJMSClient20061231.javareferstoSoapRequest20061231.xmlwhereasJMSClient20070101.javareferstoSoapRequest20070101.xml.ThecodeforJMSClient20061231isshownasfollows:
publicclassJMSClient20061231
{
privatestaticfinalStringREQUEST_FILE=
"SoapRequest20061231.xml";
publicstaticvoidmain(String[]args)throws
Exception
{
ActiveMQConnectionFactoryfactory=new
ActiveMQConnectionFactory("tcp:/localhost:61616");
ActiveMQQueuepubTopic=new
ActiveMQQueue("queue/A");
ActiveMQQueuesubTopic=new
ActiveMQQueue("queue/B");
Connectionconnection=
factory.createConnection();
Sessionsession=
connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
MessageProducerproducer=
session.createProducer(pubTopic);
MessageConsumerconsumer=
session.createConsumer(subTopic);
connection.start();
InputStreaminputStream=
JMSClient20061231.class.
getClass().getResourceAsStream(REQUEST_FILE);
intavailable=inputStream.available();
byte[]bytes=newbyte[available];
inputStream.read(bytes);
inputStream.close();
StringrequestString=newString(bytes);
producer.send(session.createTextMessage(requestString));
TextMessagetextMessage=(TextMessage)
consumer.receive(1000*10);
if(textMessage==null)
{
System.out.println("Responsetimedout.");
}
else
{
System.out.println("Responsewas:"+
textMessage.getText());
}
connection.close();
}
}
TheprogramopensthefileSoapRequest20061231.xml,readsthecontent,andthensendsthecontenttotheJMSqueueconfiguredasthewebservicegatewaychannelattheESBend.LetusalsolookattheSOAPrequestformattounderstandhowweplaceavalueforthenamespaceoftheXMLelementcorrespondingtothetargetNamespaceattributeofWSDL.Forthis,SoapRequest20061231.xmlcontentsareshownasfollows:
<?xmlversion="1.0"encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/
soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance">
<soapenv:Body>
<ns1:hellosoapenv:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns1="http://version20061231.ws.
xmlns:ns1="http://version20061231.ws.
servicemix.esb.binildas.com">
<in0xsi:type="soapenc:string"
xmlns:soapenc="http://schemas.xmlsoap.org/
soap/encoding/">
Binil
</in0>
</ns1:hello>
</soapenv:Body
</soapenv:Envelope>
Letuspayattentiontothens1namespace.Wehavegivenavalueof"http://version20061231.ws.servicemix.esb.binildas.com"forthisnamespaceandwearegoingtousethistweaktoversioncontroltheservices.YoumaywanttohavealookattheWSDLfortheremotewebservicealsotocorrelatehowthens1namespacecorrespondstothetargetNamespaceattributeofWSDL.
JMSconsumer:JMSconsumerisaservicemix-jmscomponentconfiguredintheconsumerrole.Weconfigurequeue"A"astheinputqueueforallthetestmessages.Wehavealsoconfiguredtest:extraneousWhiteSpaceTransformerasthetargetServiceforthisJMSconsumersothattheJMSconsumerwillrouteanymessagescomingtothequeue"A"totheextraneousWhiteSpaceTransformercomponent.Thisisshowninthefollowingcode:
<sm:activationSpec>
<sm:component>
<jms:component>
<jms:endpoints>
<jms:endpoint
service="test:MyConsumerService"
endpoint="myConsumer"role="consumer"
soap="false"targetService="test:
extraneousWhiteSpaceTransformer"
defaultMep="http://www.w3.org/2004/08/
wsdl/in-only"destinationStyle="queue"
jmsProviderDestinationName="queue/A"
connectionFactory="#connectionFactory">
<jms:endpoints>
</jms:component>
</sm:component>
</sm:activationSpec>
Whitespacetransformer:ThewhitespacetransformerisaServiceMixXsltComponent.Itusesastylesheettoremoveallextraneouswhitespacesfromthemessage.Thetrimmedmessageisthenroutedtothenextcomponent,whichisthetest:router.
<sm:activationSpec
componentName="extraneousWhiteSpaceTransformer"
service="test:extraneousWhiteSpaceTransformer"
destinationService="test:router">
<sm:component>
<bean
class="org.apache.servicemix.components.
xslt.XsltComponent">
<propertyname="xsltResource"
value="RemoveExtraneousWhiteSpace.xsl">
<bean>
</sm:component>
</sm:activationSpec>
TheXsltComponentusesastylesheettostripoutallextraneouswhitespacesfromthemessage.Thestylesheetisshownasfollows:
<?xmlversion="1.0"encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/
Transform"version="1.0">
<xsl:outputmethod="xml"version="1.0"
indent="no"/>
<xsl:strip-spaceelements="*">
<xsl:preserve-spaceelements="xsl:text">
<xsl:template
match="/|*|@*|processing-instruction()">
<xsl:copy>
<xsl:apply-templatesselect="@*|node()
[not(self::comment())]">
<xsl:copy>
</xsl:template>
</xsl:stylesheet>
Content-basedrouter:Thisisthecoreofthedemonstrationsetupandthisiswherethedecisionastowhichversionoftheserviceistobeinvokedtakesplace.Letuslookatthiscomponentindetail.
<eip:content-based-router
service="test:router"endpoint="endpoint">
<eip:rules>
<eip:routing-rule>
<eip:predicate>
<eip:xpath-predicate
xpath="number(substring-before(
substring-after(namespace-uri-for-prefix(
substring-before(name(/*/child::node()/
child::node()),':'),/*/child::node()/
child::node()),'http://version'),
'.ws.servicemix.esb.binildas.com'))<
20061231">
<eip:predicate>
<eip:target>
<eip:exchange-targetservice="test:
pipelineTransformBefore20061231">
<eip:target>
</eip:routing-rule>
<eip:routing-rule>
<eip:predicate>
<eip:xpath-predicate
xpath="number(substring-before(
substring-after(namespace-uri-for-prefix(
substring-before(name(/*/child::node()/
child::node()),':'),/*/child::node()/
child::node()),'http://version'),
'.ws.servicemix.esb.binildas.com'))=
20061231">
<eip:predicate>
<eip:target>
<eip:exchange-targetservice="test:
pipelineTransform20061231">
<eip:target>
</eip:routing-rule>
<eip:routing-rule>
<eip:predicate>
<eip:xpath-predicate
xpath="number(substring-before(
substring-after(namespace-uri-for-prefix(
substring-before(name(/*/child::node()/
child::node()),':'),/*/child::node()/
child::node()),'http://version'),
'.ws.servicemix.esb.binildas.com'))>
20061231">
<eip:predicate>
<eip:target>
<eip:exchange-target
service="test:pipelineTransformAfter20061231"
>
<eip:target>
</eip:routing-rule>
<eip:routing-rule>
<eip:target>
<eip:exchange-target
service="test:pipelineTransformAfter20061231"
>
<eip:target>
</eip:routing-rule>
</eip:rules>
</eip:content-based-router>
Theabovecontent-basedrouterhasthreeconditionaltargetsandadefaulttarget.Toevaluatethecontent,therouterusestheXPathpredicatewherewecanpluginourrulesintheXPathformat.
Therulewhichwepluginhereisrepeatedagain:
number(substring-before(substring-
after(namespace-uri-for-prefix(substring-
before(name(/*/child::node()/child::node()),
':'),/*/child::node()/child::node()),
'http://version'),
'.ws.servicemix.esb.binildas.com'))
ThisrulehastobeunderstoodinrelationtotheSOAPrequestwhichwehavealreadyseen.Letusrepeattherelevantportionagainhere:
<?xmlversion="1.0"encoding="UTF-8"?>
<soapenv:Envelope…>
<soapenv:Body>
<ns1:hello
xmlns:ns1="http://version20061231.ws.
servicemix.esb.binildas.com"…>
<in0xsi:type="soapenc:string"
xmlns:soapenc="http://schemas.xmlsoap.org/
soap/encoding/">Binil</in0>
</ns1:hello>
</soapenv:Body
</soapenv:Envelope>
TheXPathpredicateshownaboveisintendedtocuttheversionpartalonefromthenamespaceattributeintheSOAPrequest.Wehaveappendedyear,monthanddateinintegerformtogethertoformaneasyrepresentationofversion.Ifrequired,wecanalsoappendthetimestampportiontotheversionattributetomakeitmoreagile!Inanycase,wetaketheversionvalueandcompareitintherouter.Intheaboverouter,wehavefollowingpseudocodedrule:
if(${version}<20061231)
target:test:pipelineTransformBefore20061231
else
if(${version}=20061231)
target:test:pipelineTransform20061231
else
if(${version}>20061231)
target:test:pipelineTransformAfter20061231
else
target:test:pipelineTransformAfter20061231
Hence,dependinguponwhichversiontheSOAPrequestistargetedto,thecontent-basedrouterwillroutetherequesttotheappropriatepipelinetransform.
WehaveprovidedtwoSOAPrequestfilesfortesting.Theyare:
SoapRequest20061231.xml
SoapRequest20070101.xml
Asisevidentfromtheirnames,SoapRequest20061231.xmlhas20061231embeddedastheversioninthebodywhereasSoapRequest20070101.xmlhas20070101asitsversion.Thereadersarefreetochangethisversionvaluestotheirownfigurestotestwhetherornottherouterbehavesappropriately.Ifrequired,thereaderscanalsoaddmoreclausestotherulesinthecontent-basedrouterandunderstandthebehavior.
Transformerpipeline:ThepipelineisastandardEIPcomponentandisanintegrationbridgebetweenanIn-Only(orRobust-In-Only)MEPandanIn-OutMEP.ByreceivinganIn-OnlyMEPbythepipeline,itwillsendtheinputmessageinanIn-OutMEPtothetransformerdestinationandtheninturnforwardtheresponseinanIn-OnlyMEPtothetargetdestination.Letuslookatourpipelineconfigurationshowninthefollowingcode:
<eip:pipeline
service="test:pipelineTransformBefore20061231"
endpoint="pipelineTransformBefore20061231">
<eip:transformer>
<eip:exchange-target
service="test:soapContentRetreiver">
<eip:transformer>
<eip:target>
<eip:exchange-target
service="test:pipelineServiceBefore20061231"
>
<eip:target>
</eip:pipeline>
ThepipelinereceivestheSOAPrequestinanIn-OnlyMEP.Thisrequestisthenroutedtothetest:soapContentRetreivertargetinanIn-Out
MEP.TheresponsefromsoapContentRetreiveristhenroutedtotheexchange-targetofthepipeline,whichisanotherpipelineinthechain,test:pipelineServiceBefore20061231.
Contentretriever:ThefunctionalityofthiscomponentistoextractthepayloadpartfromtheincomingSOAPrequest.So,wetrimouttheSOAPenvelopeandbodytags,andextractonlythecontentswithinthebodyelementtobesenttothenextcomponent.WeuseaServiceMixXsltComponentasthecontentretriever.Itusesastylesheettoremoveallextraneouswhitespacesfromthemessage.Thetrimmedmessageisthenroutedtotheconsumerforthiscomponentwhichistheprevioustransformerpipeline.
<sm:activationSpec
componentName="soapContentRetreiver"
service="test:soapContentRetreiver">
<sm:component>
<bean
class="org.apache.servicemix.components.
xslt.XsltComponent">
<propertyname="xsltResource"
value="SoapRequest-To-Request.xsl">
<bean>
</sm:component>
</sm:activationSpec>
ThisXsltComponentalsousesastylesheettoextractthepayloadfromtheSOAPmessage.Thestylesheetisshownasfollows:
<xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/
envelope/">
<xsl:outputmethod="xml">
<xsl:templatematch="">
<xsl:copy-of
select="soapenv:Envelope/soapenv:Body/*">
<xsl:template>
</xsl:stylesheet>
Theoutputofthiscomponentisshownasfollows:
<ns1:hello
soapenv:encodingStyle="http://schemas.xmlsoap.org/
soap/encoding/"
xmlns:ns1="http://version20061231.ws.
servicemix.esb.binildas.com">
<in0xsi:type="soapenc:string"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
Binil
</in0>
</ns1:hello>
Servicepipeline:Thiscomponentisverysimilartothetransformerpipelineseenabove.Letuslookattheconfigurationandthenunderstanditmore:
<eip:pipeline
service="test:pipelineServiceBefore20061231"
endpoint="pipelineServiceBefore20061231">
<eip:transformer>
<eip:exchange-target
service="version20061231:IHelloWebService">
<eip:transformer>
<eip:target>
<eip:exchange-target
service="test:MyProviderService">
<eip:target>
</eip:pipeline>
ThispipelinewillsendtheSOAPpayloadalone(withouttheSOAPenvelope)asanIn-OutMEPtotheeip:exchange-targetwhichisversion20061231:IHelloWebService.Anyresponseisthenroutedtothetest:MyProviderService,whichistheoutputqueuefortheclient.
HTTPprovider:TheHTTPproviderisaservicemix-httpusedforHTTPorSOAPbindingofservicesandcomponentsintotheServiceMixNMR.AproviderroleimpliesthattheNMRistheconsumertothecomponent.Hence,theNMRsendsoutanIn-OuttotheHTTPproviderand
theHTTPproviderinturnroutesthemessagetotheremotewebservice.ThewebservicegetsinvokedandtheresponsereceivedisroutedbacktotheconsumeroftheHTTPproviderwhichistheservicepipelinedescribedabove.TheHTTPproviderconfigurationisshownasfollows:
<http:endpoint
service="version20061231:IHelloWebService"
endpoint="HelloWebService"role="provider"
locationURI="http://localhost:8080/
AxisEndToEnd20061231/services/
HelloWebService20061231"soap="true"
soapAction=""
wsdlResource="http://localhost:8080/
AxisEndToEnd20061231/services/
HelloWebService20061231?WSDL"/>
Here,thelocationURIreferstotheactualURLwherethewebserviceishosted.Aswehavetwoversionsofthewebserviceshostedtotesttheversionfunctionality,wealsohaveanotherHTTPproviderpointingtotheotherwebserviceversionsasshowninthefollowingcode:
<http:endpoint
service="version20070101:IHelloWebService"
endpoint="HelloWebService"role="provider"
locationURI="http://localhost:8080/
AxisEndToEnd20070101/services/
HelloWebService20070101"soap="true"
soapAction=""
wsdlResource="http://localhost:8080/
AxisEndToEnd20070101/services/
HelloWebService20070101?WSDL"/>
Remotewebservice:Thissectionneedssomedetailedexplanation,asweneedtolookintomechanismsonhookingtheversioncontrolintoourdevelopmentengineeringprocessitself.
WehaveseenthatthereareoptionstosetthetargetNamespaceattributeontheWSDL.Itisbetterto
hookthistothetoolinfrastructureassociatedwithwebservicegenerationandmosttoolsincludingtheApacheAxisprovidesmechanismstodothis.Letuslookintothatnow.
AxisprovidestheJavaorg.apache.axis.wsdl.Java2WSDLclasstohelpusingeneratingWSDLfromtheJavainterfacesusedforcreatingthewebservice.TheWSDLgenerationcanbecontrolledusingtheparameters.Twoparametersthatareimportanttousarethefollowing:
-n,--namespace<targetnamespace>
indicatesthenameofthetargetnamespaceoftheWSDL.
-p,--PkgToNS<package><namespace>
indicatesthemappingofapackagetoanamespace.
Ifapackageisencounteredthatdoesnothaveanamespace,theJava2WSDLemitterwillgenerateasuitablenamespacename.Thisoptionmaybespecifiedmultipletimes.Bydefault,Java2WSDLwilltakethepackagenameofthewebserviceinterfaceclass.
Now,weneedtoversioncontrolthewebserviceexposureaswellasthewholewebservicegenerationprocess.Hence,wehavearrangedourwebserviceartifacts(sourcefiles,andtheirpackagenamestoo)inafolderstructurewhichrepresentstheversion.Bydoingthatwedon'tneedtocontrolfurtherthe
Java2WSDLprocessusingtheaboveparameters,insteadthe"versioned"packagenameoftheclassesisusedtodefinethetargetNamespaceattributeontheWSDL.
Wehavetwoversions,namely20061231and20070101,referringtothetwoversionsoftheservice,onedefinedonthe2007NewYear'seveandtheotheronthenewyearitself.
LetuslookatthisintheWSDLsgeneratedforthetwowebserviceswehave:
InHelloWebService20061231.wsdlwehavethefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="http://version20061231.ws.
servicemix.esb.binildas.com"…>
<wsdl:types>
<schemaelementFormDefault="qualified"
targetNamespace="http://version20061231.ws.
servicemix.esb.binildas.com"
xmlns="http://www.w3.org/2001/XMLSchema">
</schema>
</wsdl:types>
<wsdl:messagename="helloResponse">
<!--othercodegoeshere-->
</wsdl:message>
<wsdl:portTypename="IHelloWeb">
<!--othercodegoeshere-->
</wsdl:portType>
<wsdl:binding
name="HelloWebService20061231SoapBinding"
type="impl:IHelloWeb">
<!--othercodegoeshere-->
</wsdl:binding>
<wsdl:servicename="IHelloWebService">
<wsdl:port
binding="impl:HelloWebService20061231SoapBinding"
name="HelloWebService20061231">
<wsdlsoap:address
location="http://localhost:8080/
AxisEndToEnd20061231/services/
HelloWebService20061231">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
InHelloWebService20070101.wsdl,wehavethefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="http://version20070101.ws.
servicemix.esb.binildas.com"...>
<wsdl:types>
<schemaelementFormDefault="qualified"
targetNamespace="http://version20070101.ws.
servicemix.esb.binildas.com"
xmlns="http://www.w3.org/2001/XMLSchema">
</schema>
</wsdl:types>
<wsdl:messagename="helloRequest">
<!--othercodegoeshere-->
</wsdl:message>
<wsdl:portTypename="IHelloWeb">
<!--othercodegoeshere-->
</wsdl:portType>
<wsdl:binding
name="HelloWebService20070101SoapBinding"
type="impl:IHelloWeb">
<!--othercodegoeshere-->
</wsdl:binding>
<wsdl:servicename="IHelloWebService">
<wsdl:port
binding="impl:HelloWebService20070101SoapBinding"
name="HelloWebService20070101">
<wsdlsoap:address
location="http://localhost:8080/
AxisEndToEnd20070101/services/
HelloWebService20070101">
<wsdl:port>
</wsdl:service>
</wsdl:definitions>
IfyouobservetheseWSDLfilescloselyyoucanseethatthewsdlsoap:addresspointstodifferentaddressesfordifferentversionsoftheservice.IfweexposetheWSDLassuchtoconsumers,thentheconsumerswillbetemptedtoaccessthewebserviceusingthe"Multipleendpointaddress"approach.However,wewanttodemonstratethecovenant-basedapproachandforthatwecaneditthewsdlsoap:addresselementintheWSDLsofboththewebservicestopointtothesameendpointaddress(theJMSconsumeraddressasisinourcase,oraHTTPconsumeraddress).Ifso,ourcontent-basedrouterwilldotherest.
JMSprovider:TheJMSproviderissimilartotheJMSconsumeralreadydiscussedandtheconfigurationislistedasfollows:
<jms:endpoint
service="test:MyProviderService"
endpoint="myProvider"role="provider"
soap="false"destinationStyle="queue"
jmsProviderDestinationName="queue/B"
connectionFactory="#connectionFactory"/>
Here,werefertheoutputqueueas"B".Thisisthequeueto
wheretheServicepipelinetargetstheSOAPresponsefromtheremotewebservice.TheJMSclientcanretrievetheresponsefromthisqueue.
DeployandRuntheSampleTobuildtheentiresample,itiseasiertochangedirectorytothetop-levelfolderandexecutethebuild.xmlfileprovidedthere.Asafirststep,ifyouhaven'tdoneitbefore,findexamples.propertiesfileprovidedalongwiththesampleandchangethepathsaccordinglytomatchyourdevelopmentenvironment.Thenexecutethefollowing:
cdch14\WebServiceVersioning
ant
Thiswillbuildthefollowingbothversionsofwebserviceandplacethedeployablewarfileinthedistfolderasshownasfollows:
ch14\WebServiceVersioning\01_WebService20061231\d
ist\AxisEndToEnd20061231.war
ch14\WebServiceVersioning\02_WebService20070101\d
ist\AxisEndToEnd20070101.war
Youcantransferthesewarfilesintothewebappsfolderofyourfavoritewebcontainerandrestartthewebserver.MakesureyourwebservicesaredeployedcorrectlybytryingoutthefollowingURLs:
http://localhost:8080/AxisEndToEnd20061231
/services/HelloWebService20061231?WSDL
http://localhost:8080/AxisEndToEnd20070101
/services/HelloWebService20070101?WSDL
Nowtherearealsotestclientsprovidedforyoutotestthetwoversionsofthewebservice.Totestthat,dothefollowing:
Totesttheversion20061231oftheservice,executethefollowingcommands:
cd
ch14\WebServiceVersioning\01_WebService20061231
antrun
Totesttheversion20070101oftheservice,executethefollowingcommands:
cd
ch14\WebServiceVersioning\02_WebService20070101
antrun
Asthesecondstep,youneedtobringupyourServiceMixESB.Beforedoingthatyouhavetoplug-intheSaxonXPathFactoryclasstotheJavaruntime.Thiscanbedoneintwosteps:
PlacetheSaxonjarsin%SERVICEMIX_HOME%\lib\optionalfolder.
Inthe%SERVICEMIX_HOME%\bin\servicemix.batfile,addthefollowingentry:
setBOOT_OPTS=%BOOT_OPTS%-Djavax.xml.xpath.XPathFactory:http://java.sun.c
om/jaxp/xpath/dom="net.sf.saxon.xpath.XPathFact
oryImpl"
NowbringupServiceMixbyexecutingthefollowingcommands:
cdch14\WebServiceVersioning
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
YourwebserviceandESBarereadynowtoserveclients.Twoclientsareprovidedtotestthewebservice.Youcantestthembyexecutingthefollowingcommands:
cdch14\WebServiceVersioning
antrun1
and
cdch14\WebServiceVersioning
antrun2
run1willtestthewebservicerequestingversion20061231andrun2willtestversion20070101.Boththeseclientswillsendmessagestothecovenantandthecovenantwillroutetherequeststodifferentversionsofthewebservice.
ForyourconveniencewehavealsoprovidedtwoHTTPclientswhichwilldirectlysendrequeststothedifferentversionsofthewebserviceendpointaddressesconfiguredin
theESB.Theyarejustforyourconvenienceandtheyarenotintendedtotestthewebserviceversioningmechanismperse.Theseclientsare:
cdch14\WebServiceVersioning\Client20061231.html
and
cdch14\WebServiceVersioning\Client20070101.html
WebServiceVersioningOperationalPerspectiveAttheoperationsperspective,wecanusetoolstoedittheWSDLstoreflectthischangeandthenplacealltheWSDLsinarepositoryfortheconsumerstofindorevensupplytheseWSDLstotheconsumers.TheconsumerscanthenusetheirconventionaltoolstogenerateclientstubsandsendSOAPrequeststoaccesstheservice.Theversionaspectisnotrevealedtotheclients,insteadtheyarelimitedtotheWSDLs.
AsweareusinganESBasthemiddlewaremessaginginfrastructure,anotheroptionisthattheWSDLscanberetrievedfromtheiroriginalsource(forexample,http://localhost:8080/AxisEndToEnd20061231
/services/HelloWebService20061231?WSDL)ondemandbasisfromtheclient.Moreover,doanXSLtransformtoreplacethedifferentendpointaddresseswithasingle
covenantaddressandsupplythem.
SummaryWhiletheneedtoversionaserviceisstilltobedebated,oneaspectwhichweallneedtoacceptisthatservicesneedtobemaintainedinmultiplevariantstosatisfymultipleclassesofconsumers.Servicerequestcanbeenhancedtoincludeadditionalinformationwhichwillhelpproviderstoapplyrulestorouterequeststotheappropriateclassorvariantoftheservice.Whileitistrickytohandlethiskindofroutingusingatrivialhandlerorinterceptor-level,anESBprovidesyoualltherequireddesignpatternsandhookstoenforcecontent-basedrouting.Thenneithertheserviceprovidernortheserviceconsumerneedstobeawareofthesecomplexities.ThesedesignpatternsandhooksaregroupedunderthebroaderheadingofEIPandthenextchapterisgoingtolookatthemingreaterdepth,againwithworkingcodesamples.
Chapter15.EnterpriseIntegrationPatternsinESBBynowyouwillappreciatethefactthatintegrationisnotsimple.Now,howcanyoumakeitmanageableand/orrepeatableandthussimplifyintegration?Haven'tyoucomeacrossthesameproblemintraditionalsoftwareengineeringbefore?Howdidyoumanagetheproblemthen?Yes,IamreferringtonothingelseotherthanPatterns.
Inthischapter,wearegoingtocoverthefollowing:
EAIpatternsingeneral
EAIpatternsinServiceMix
WorkingcodedemonstratingEAIpatterns
EnterpriseIntegrationPatternsEnterpriseintegrationhastobemadesimpler.WeneedtoapplybestpracticestestedandproveninthetraditionalsoftwareengineeringparadigmslikeOOPtoenterpriseintegrationscenariosalso.ReusabilityisaprimeconcerninallITdesignrelateddecisionsandthisreusabilityhastohappenatmultiplelevelsincludingarchitecture,design,
implementation,andtesting.Whilewearchitectordesignforintegrationproblems,onewayofreusingtheexistingartifactsistoabstractoutthecommonmethodsusedforsolutionsandapplythemagainandagainforrecurring,similarproblems—wecallthisEIP.Letusdelvemoreintothis.
WhatareEAIPatterns?Eventhoughwedoenterpriseintegrationdailyknowinglyorunknowingly,ittakessomeexperienceandaholisticapproachtoseparateouttheintegrationaspectsfromtheroutineapplicationdevelopmentaspectsinasystemsenvironment.Whenweunderstandthisdifference,wehavetakenthefirststepinrecognizingEAIasaseparatestream,infactaspecializedstreamwhichrequiresspecificskillsetstolookatsystemsandservicesfromanintegrationpointofview.
Wewillstartthinkingintermsofconnectors,brokers,ormessagerouterswhichhaveaveryspecificroleandresponsibilityintheintegrationdomain.Theseareintegrationblockswhichwhencombinedtogetherindifferentwayswillgiveoutnewstylesorpatternsofmessageexchange.Hence,EAIpatternsarenuggetsofadvicemadeoutofaggregatingbasicMEPelementstosolvefrequentlyrecurringintegrationproblems.ForeverypracticalpurposethesearesimilartodesignpatternsandwecanlookatEAIpatternsasdesignpatternsforsolvingintegrationproblems.
EAIPatternsBookandSiteInwritingachapterdiscussingEAIpatterns,IhavetoinvariablypointtothegreatbookonEAIpatternsbyGregorHohpeandBobbyWoolf.Infact,thisbookisacollectionofabout65patterns,allprovidingmeanstosolvethedaytodayintegrationproblems.Eachofthepatternsisdescribedusingthefollowingsubheadings:
Name
Icon
Context
Problem
Forces
Solution
Sketch
Results
Next
Sidebars
Examples
Thebeautyofthesepatternsisthattheysolvenotonlycommonintegrationproblemsbutalsoenabletheintegrationarchitecttocombinethemtogethertocreatedesigns.Usingthesetheycansolveproblemswhichtheyhadneverthoughtabout.
Equallyimportantistheinfluenceofthediagramsandnotationsintheintegrationpatterns.Thishelpsarchitectsanddesignerstoshareacommonvocabularyinintegration.TheEAIbookandtheassociatedsiteprovidenotationswhichhaveacertain"sketch"quality.ThenitisnotrequiredtoreadhundredsofpagesofamanuallikethatofUMLtounderstandanduse.However,duetotheobjective-orientednotations,itiseasytoconveytheessenceofthepatterntothereaderataquickglance.Forexample,letuslookintoafewnotationsgiveninthefollowing:
Letusnowlookintosimpledefinitionsforthepatternscorrespondingtothenotationsshownabove:
Aggregator:Anaggregatorisusedtocollectandstoreindividualmessagepartsuntilacompletesetofco-relatedmessagepartshasbeenreceived.Oncealltherelatedpartshavebeenreceived,theyareaggregatedtogethertoformasinglemessage.
Splitter:Asplittercansplitoutacompositemessageintoaseriesofindividualmessageparts.
WireTap:Awiretapcanconsumemessagesfromasingleinputchannelandpublishtheunmodifiedmessagetotwooutputchannels.
Havinggonethroughthesimpleexplanationfortheabovenotations,ifyounowlookatthenotationsperse,youwillappreciatehoweasyisittocorrelatethefunctionalitywithitsnotation.
ServiceMixEAIPatternsServiceMixandJBIareallaboutintegratingbusinessservices.LetusnowseewhatServiceMixhastoofferintermsoftheEAIpatterns.
WhyServiceMixforEAIPatterns?ServiceMixprovidestheservicemix-eipcomponentasastandardJBI-compliantcomponent.ThisprovidesimplementationsformanyofthepatternsdiscussedintheEAIpatternsbook.WhenIfirstreadtheEAIpatternsbook,Iwaswonderingwhetherwehaveallthesepatternstogetherinsomereusableform,otherthanjustpatternsanddiagrams.Butasweallagree,patternsarenuggetsofguidelineswhichwecanimplementinmanyways,usinganytechnologyorplatform.
Infact,ifwelookatmanyMOMforintegrationssuchasWebsphereMQ,MicrosoftBiztalk,TIBCO,Webmethods,andMicrosoftMQ,theyalreadyprovidemanyofthesepatternsattheframework-level.Perhaps,wedidn'tnoticethemaspatternsinthefirstgo,butsurelyasexperiencebuildsupwecannotmissarepeatedwayofaddressingaproblemofaparticularnature.
MonthsaftermyfirstreadingoftheEAIpatternsbookIstartedevaluatingafewoftheSOI-basedproducts,especiallyintheJavaworldincludingMuleandtheESBframework.ThebestpartoftheseframeworksisthatwehavemanyoftheEAIpatternsintheformofcode!Believeme,ifIweretohave
usedtheseintegrationframeworksafewyearsback,itwouldhavesavedmemanymanmonths!Today,Iamwonderinghowmuchcodeourteamhaswrittenpreviouslyforreceiving,selecting,storing,andthensequencing,andaggregatingmultiplepassengernamelists(PNL)messagesforamajorairline.Lookattheflowgiveninthefollowing:
Here,IusedEAIpatternblockstoconnectthemtogethertocreatemyowndesignformyPNLpartmergingproblem.Forthis,wenolongerwriteJavaor.NETcodetoparsemyentirePNLmessagepart,selectthem,andstorethemandfinallywhenallpartsarereached,toresequencethemtoformthefullPNL.Instead,astheseindividualproblemsarealreadyaddressedasEAIpatterncomponents,Ijustneedtoselecttherequiredblocks,configure,andconnectthemtogetherandroutemymessagethroughthat.Don'tyouthinkthatisasmartwayofdoingthings?
Icanunderstand,youmaynotagreeifyouarereadingabouttheEAIpatternsforthefirsttime.However,Icanguaranteethatonceyoufinishreadingthischapterandalsoacoupleofmorechaptersinthisbookwhichsolvessomeofthemajorheadachesintheindustry,youwillbeinabetterpositiontoappreciatetheimportanceofEAIpatternsinintegration.
Forexample,buildingaprotocolbridgetobringreliabilitytoawebservicechannelortoimplementawebserviceversioning
mechanism,younomorethinktraditionally.However,IneedtoremindyouthatEAI,EAIpatterns,andMOMaregreatenablersforSOAandSOI,butmaynotbethesolutionforeveryproblemathand.Inotherwords,noneofthesepatternsorframeworksisgoingtoreplacethejudiciousdecisionyouareobligedtotakeasadesigneroranarchitect,topickthebesttechnologyorframeworkstosolveyourproblems.
Hence,byanychanceifyoudecidethatMOMisthewaytogoandyouwanttouseServiceMixasyourESBmiddleware,youcanusemanyEAIpatternblocksavailablehere.TheServiceMixservicemix-eipcomponentisaroutingcontainerontowhichyoucandeployyourownEAIpatternsorcombinationofpatternstosolvecomplexroutingorMEPproblems.
Forexample,youmaysometimeswanttotransformanIn-OutMEPtoacombinationofIn-OnlyMEPoryoumaywanttorouteyourmessagesdestination.Parallellyyoualsowanttodeliveracopyofthemessagetoatracecomponentinbetween.Don'teverwritecodefortheseinServiceMix,insteadrouteyourmessagesthroughasuitableEAIpatternblockdeployedontoservicemix-eip.
ServiceMixEAIPatternsConfigurationWecanconfigureservicemix-eipeitherinaSUasastandardJBIcomponentorusingtheservicemix.xmlconfigurationfile.Thisisshowninthefollowinglist:
Configureservicemix-eipasastandardJBIcomponent:servicemix-eipsupportsthestandardXBean-baseddeployment.Forthis,thexbean.xmlfilewillhavethefollowingentry:
<beans
xmlns:eip="http://servicemix.apache.org/eip/1.0">
<!--configureyourEAIPatterncomponents
here-->
</beans>
Configureservicemix-eipusingtheservicemix.xmlfile:
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:test="http://test.eip.servicemix.esb.binildas.com">
<sm:container...>
<sm:activationSpecs>
<sm:activationSpec>
<sm:component>
<eip:component>
<eip:endpoints>
<!--configureEAIPatterncomponentshere--
>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
</beans>
EAIPatterns—CodeandRunSamplesinESBThemainEAIpatterncomponentssupportedbyServiceMixarelistedasfollows:
Content-basedrouter
Contentenricher
XPathsplitter
Messagefilter
Splitaggregator
Pipeline
Wiretap
Staticrecipientlist
Staticroutingslip
LetusnowconfigureEAIpatterncomponentsintheServiceMixandrunthesamples.Allthesamplesarearrangedinsubfoldersunderch15\.Makesurethatyoueditexamples.PROPERTIESandchangethepathstheretomatchyourdevelopmentenvironmenttobuildthesamples.
Content-basedRouterAcontent-basedrouterconsumesamessagefromonemessagechannel.Basedonasetofconditionsontheheadersorthebodycontentofthemessage,itrepublishesthemessageontoadifferentmessagechannel.
NOTATION
EXPLANATIONThemessagerouterinspectsthecontentsofthemessageandroutesthemessagetomultiplechannels.Whiledoingso,therouterwillnotalterthemessagecontents.Whileinspecting,theroutercanlookintoafieldinthemessagebodyorthemessageheader.Usually,aconditionoraruleisattachedtotherouterwhichwilltryamatchwiththefieldinthemessage.Hencethisrulematchinghookistobedesignedasextensibleandisthetargetofconstantmaintenancewhenwewanttoaddmorerulesorwhenwewanttoplug-inmorechannelsmatchingtherules.
ILLUSTRATIVEDESIGNLetusconsidertheAcmeCompanyprovidingthewebinterfacetoendcustomerstoplaceordersforbuyingthegadgetsonline.TheAcmeorderinggatewaycanprovideasinglechannelforalltheincomingmessagesduetomaintenanceandsecurityreasons.Nowweneedamechanismtosegregateoutordersfordifferentkindsofgadgets.Eachkindofgadgets(apparelsandelectricals,forexample)hasitsowninventorysystem.Henceweneedtoroutedifferentkindsoforderstotheirrespectiveinventorysystems.
Weplug-inacontent-basedrouterandattachmultiple
outgoingchannelstothisrouter.Therouterwilllookatthemessagecontentsandidentifythekindoforder.Basedonthat,itwillroutethemessagetotheirrespectiveoutgoingchannelsfromwheretherespectiveinventorysystemscanpickupthemessages.Thisisshowninthefollowingfigure:
SAMPLEUSECASEThesampleusecasehasasetofcomponentsasshowninthefollowingfigure:
Letusnowlookintotheindividualcomponentsindetailinthefollowinglist:
JMSclient:ThisisanormalexternalJMSclient,placingdifferentXMLmessagesontotheJMSconsumercomponentconfiguredwithintheESB.
JMSconsumer:Thisisaservicemix-jmslisteningonqueue"A".Anyincomingmessagestothisqueuewillberoutedtothenextcomponentinthe
flowchain,thecontent-basedrouter.
Content-basedrouter:Thecontent-basedrouterisaservicemix-eipcomponent.BasedonthecontentoftheXMLmessageitreceives,itwillroutethemessage,unaltered,toanyoneamongstthesetofReceivercomponentsconfigured.
Receiver:Thereceivercomponentisacustomtransformcomponent.AnymessageitreceiveswillbeloggedintotheconsoleandthenechoedbywritingbacktotheoutmessageoftheIn-Out.Theoutmessageisplacedintheoutqueue.
JMSprovider:Thisisaservicemix-jmslisteningonqueue"B".ThereceivercomponentwillplaceitsoutmessageontothisqueuefromwheretheJMSclientcanpickup(eventhoughinthissamplewedon'tpickupthemessages).
SAMPLECODEANDCONFIGURATIONWeconfigurethecontent-basedrouterintheservicemix.xmlfile,alongwithothercomponentsdescribedabove.Thisisshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns="http://xbean.org/schemas/spring/1.0"
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:test="http://cbr.eip.servicemix.apache.binildas.com"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0">
<classpath>
<location>.</location>
</classpath>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml">
<beanid="propertyConfigurer"
class="org.springframework.beans.
factory.config.PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
</bean>
<sm:containername="jbi"
monitorInstallationDirectory="false"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpec>
<sm:component>
<jms:component>
<jms:endpoints>
<jms:endpointservice="test:MyConsumerService"
endpoint="myConsumer"role="consumer"
soap="false"targetService="test:router"
defaultMep="http://www.w3.org/2004/
08/wsdl/in-only"destinationStyle="queue"
jmsProviderDestinationName="queue/A"
connectionFactory="#connectionFactory">
<jms:endpointservice="test:MyProviderService"
endpoint="myProvider"role="provider"
soap="false"destinationStyle="queue"
jmsProviderDestinationName="queueB"
connectionFactory="#connectionFactory">
<jms:endpoints>
</jms:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver1"
service="test:receiver1"
destinationService="test:MyProviderService">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>1</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver2"
service="test:receiver2"
destinationService="test:MyProviderService">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>2</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver3"
service="test:receiver3"
destinationService="test:MyProviderService">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>3</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver4"
service="test:receiver4"
destinationService="test:MyProviderService">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>4</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpecid="servicemix-eip">
<sm:component>
<eip:component>
<eip:endpoints>
<eip:content-based-routerservice="test:router"
endpoint="endpoint">
<eip:rules>
<eip:routing-rule>
<eip:predicate>
<eip:xpath-predicatexpath="number(hello@id)<
2">
<eip:predicate>
<eip:target>
<eip:exchange-targetservice="test:receiver1">
<eip:target>
</eip:routing-rule>
<eip:routing-rule>
<eip:predicate>
<eip:xpath-predicatexpath="number(hello@id)=
2">
<eip:predicate>
<eip:target>
<eip:exchange-targetservice="test:receiver2">
<eip:target>
</eip:routing-rule>
<eip:routing-rule>
<eip:predicate>
<eip:xpath-predicatexpath="number(hello@id)>
3">
<eip:predicate>
<eip:target>
<eip:exchange-targetservice="test:receiver4">
<eip:target>
</eip:routing-rule>
<eip:routing-rule>
<eip:target>
<eip:exchange-targetservice="test:receiver3">
<eip:target>
</eip:routing-rule>
</eip:rules>
</eip:content-based-router>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
<beanid="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<propertyname="brokerURL"
value="tcp://localhost:61616">
<bean>
</beans>
ThecomponentsconfiguredintheaboveJBIconfigurationhavealreadybeenexplainedintheprevioussection.Weneedtodeclaretheeipnamespaceasxmlns:eip=http://servicemix.apache.org/eip
/1.0.Wewillalsousetheservicemix-jmscomponentforwhichwedeclaretheJMSnamespaceasxmlns:jms=http://servicemix.apache.org/jms
/1.0.
TheMyReceiverclassisshownasfollows:
publicclassMyReceiverextends
TransformComponentSupportimplements
MessageExchangeListener
{
privateStringname;
publicvoidsetName(Stringname){this.name=
name;}
publicStringgetName(){returnname;}
protectedbooleantransform(MessageExchange
exchange,NormalizedMessagein,NormalizedMessage
out)throwsMessagingException
{
NormalizedMessagecopyMessage=
NormalizedMessagecopyMessage=
exchange.createMessage();
getMessageTransformer().transform(exchange,in,
copyMessage);
Sourcecontent=copyMessage.getContent();
StringcontentString=null;
if(contentinstanceofDOMSource)
{
contentString=XMLUtil.node2XML(((DOMSource)
content).getNode());
}
if(contentinstanceofStreamSource)
{
contentString=
XMLUtil.formatStreamSource((StreamSource)
content);
}
System.out.println("MyReceiver.transform("+name
+").contentString="+contentString);
out.setContent(newStringSource(contentString));
returntrue;
}
}
TheMyReceiverclassprintsoutthemessageandechoesthesamemessageback.
DEPLOYANDRUNTHESAMPLETobuildthesample,changedirectorytoch15\01_ContentBasedRouterandtypethefollowing:
ant
Thiswillcompileallthefiles,includingtheJMSclient
program.Nowtotestthesample,firstbringServiceMixupbyexecutingthefollowingcommands:
cdch15\01_ContentBasedRouter
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
Nowinadifferentcommandpromptexecuteantrun,asshownhere:
cdch15\01_ContentBasedRouter
antrun
TheJMSclientprogramconsolewillprintoutthemessagesitsendstotheESB.Thisisshowninthefollowingscreenshot:
Now,havealookatthecontent-basedrouter.Asshowninthecontent-basedrouterconfiguration,wehavethecontent-basedrouterrulesembeddedastheXPathpredicates.Basedonthematchinthemessagecontent,therouterwillroutethemessagetotheirrespectivedestinations(Receiver1or2or3
or4).TheESB-sideconsoleprintoutvalidatesthisasshowninthefollowingscreenshot:
ContentEnricherThecontentenrichersupplementstheoriginalmessagewithmorerelatedinformationretrievedfromtheothersources.Theoriginalmessagewillbealteredtocontainenrichedinformation.
NOTATION
EXPLANATIONSometimesamessagemaynotcontainalltherequiredinformationforthenextprocessingsteptoactorthenext
processingrequiredmoreadditionalinformationtobeappendedtotheincomingmessage.Insuchscenarios,thecontentenrichercanappendtheadditionalinformationtotheoriginalmessageandthensendtothenextlinkintheprocessingchain.
ILLUSTRATIVEDESIGNTheAcmeonlinecustomersatthetimeofcheckoutwillentercreditcarddetails.TheAcmebackendwouldneedtodocreditauthorization.However,thedataenteredbythewebpagecustomersmightbeminimalandfortheactualauthorizationwemightneedtoaddmoredetailssuchasSSN,beforetherequestisroutedtoCreditCheckService.AContentEnrichercangetthecustomeridentificationdata(customerkey)fromtheincomingmessageandretrievetheextradetailsfromalocalresourcestore.Theextradetailscannowbeappendedtotheoriginalmessageandthenroutedtothetargetservice.Thewholesetupisshowninthefollowingfigure:
SAMPLEUSECASE
ThefollowingfigureillustrateshowvariouscomponentscanbeassembledintheJBIbusforoursampleusecase:
Thesampleusecasewillhavefollowingcomponents:
JMSclient:ThisisanormalexternalJMSclient,placingXMLmessagesontotheJMSConsumercomponentconfiguredwithintheESB.
JMSconsumer:Thisisaservicemix-jmslisteningonqueue"A".AnyincomingmessagestothisqueuewillberoutedtothenextcomponentintheflowchainwhichistheContentEnricher.
Contentenricher:TheContentEnricherrouterisaservicemix-eipcomponent.Itenrichestheoriginalmessagewithadditionalinformation.TheenrichedmessagewillbeplacedbackintheJMSProviderqueue.
Contentappender:TheContentAppenderisacustomtransformcomponent.ItprovidesaresultElementwithnametest:kerberosticketsothatthecontentenrichercanenrichtheoriginalmessagewiththisadditionalresultElement.
JMSprovider:Thisisaservicemix-jmslisteningonqueue"B".TheContentEnrichercomponentwillplaceitsoutmessageintothisqueuefromwheretheJMSClientcanpickup.
SAMPLECODEANDCONFIGURATIONWeconfigurethecontentenricherintheservicemix.xmlfile,alongwithothercomponentsdescribedabove.Thecontentofthisfileisshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns="http://xbean.org/schemas/spring/1.0"
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:test="http://cer.eip.servicemix.esb.binildas.com"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0">
<classpath>
<location>.</location>
</classpath>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml"/>
<beanid="propertyConfigurer"
class="org.springframework.beans.
factory.config.PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<sm:containername="jbi"
monitorInstallationDirectory="false"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpec>
<sm:component>
<jms:component>
<jms:endpoints>
<jms:endpointservice="test:MyConsumerService"
endpoint="myConsumer"role="consumer"
soap="false"
targetService="test:contentEnricher"
defaultMep="http://www.w3.org/2004/
08/wsdl/in-only"destinationStyle="queue"
jmsProviderDestinationName="queue/A"
connectionFactory="#connectionFactory">
<jms:endpointservice="test:MyProviderService"
endpoint="myProvider"role="provider"
soap="false"destinationStyle="queue"
jmsProviderDestinationName="queueB"
connectionFactory="#connectionFactory">
<jms:endpoints>
</jms:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpecid="servicemix-eip">
<sm:component>
<eip:component>
<eip:endpoints>
<eip:content-enricher
service="test:contentEnricher"
endpoint="endpoint"
enricherElementName="test:subject"
requestElementName="test:principal"
resultElementName="test:credential">
<eip:enricherTarget>
<eip:exchange-target
service="test:contentAppender">
<eip:enricherTarget>
<eip:target>
<eip:exchange-target
service="test:MyProviderService">
<eip:target>
</eip:content-enricher>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpec
componentName="contentAppender"
service="test:contentAppender">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="ContentAppender">
<constructor-argref="jbi">
<bean>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
<beanid="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<propertyname="brokerURL"
value="tcp://localhost:61616">
<bean>
</beans>
WhenweconfigurethecontentenricherwecanspecifytheenricherElementName,requestElementName,andtheresultElementName.Theoutputofthecontentenricherwillbewrappedwithintheseelementsasseeninthesampleoutputinthefollowingscreenshot.LetusalsolookattheContentAppenderJavaclass:
publicclassContentAppenderextends
ComponentSupportimplements
MessageExchangeListener{
privateJBIContainercontainer;
publicContentAppender(JBIContainercontainer)
{
this.container=container;
}
}
publicvoidonMessageExchange(MessageExchange
exchange)
throwsMessagingException
{
if(exchange.getStatus()==
ExchangeStatus.ACTIVE)
{
booleantxSync=exchange.isTransacted()&&
Boolean.TRUE.
equals(exchange.getProperty(JbiConstants.SEND_SYNC));
NormalizedMessageout=exchange.createMessage();
out.setContent(newStringSource("<?xml
version='1.0'encoding='UTF-8'?>
<test:kerberosticketxmlns:test=
\"http://xslt.servicemix.apache.binildas.com\">
123456789</test:kerberosticket>"));
exchange.setMessage(out,"out");
if(txSync)
{
sendSync(exchange);
}
else
{
send(exchange);
}
}
}
}
Here,wewritetheinformationtoenrichtheoriginalmessagetotheout.Inactualscenarios,wemaywanttoretrievesomekeyfromtheincomingmessage,retrievemoredatafromalocalresourceusingthiskeyandgeneratetheadditionalinformation.
DEPLOYANDRUNTHESAMPLETobuildthesample,changedirectorytoch15\02_ContentEnricherandtypeant.Thisisshownasfollows:
cdch15\02_ContentEnricher
ant
Thiswillcompileallthefiles,includingtheJMSclientprogram.Nowtotestthesample,first,bringtheServiceMixupbyexecutingthefollowing:
cdch15\02_ContentEnricher
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
Nowinadifferentcommandpromptexecuteantrun.
cdch15\02_ContentEnricher
antrun
TheJMSclientprogramconsolewillprintoutthemessagesitsendstotheESB.Italsoprintsouttheresponsemessagefromthecontentenricher.TheJMSclientconsoleisshowninthefollowingscreenshot:
XPathSplitterAnXPathsplitterisbasedontheoriginalsplitterEAIpattern.Asplittercanidentifyrepeatingelementsinamessageandsplitthemessageandpublisheachelementpartasseparatemessagestoadifferentchannel.Thesplittercanalsoseparateoutnon-repeatingelements,insuchcasethepublishedmessagewillbeasubsetoftheoriginalmessage.XPathsplitterusesXPathtofindtherepeatingelementpattern.
NOTATION
EXPLANATION
Manycompositedocumentslikeafullairlinepassengernamelistoranorderwithmanyorderitemswillcontainrepeatingelements.Sometimeswemayneedtoprocesseachoftheserepeatingelementsseparately.AnXPathsplittercansplitthecompositemessageintoindividualpartsbasedontherepeatpatternandpublishesthepartsontodifferentdestinations.
ILLUSTRATIVEDESIGNUsingtheAcme'sonlinee-commercepages,acustomercanaddmultipleitemstotheshoppingcartandattheendoftheshoppingtriphecancheckout.Thiswillsubmitasingleorderinthebackend,buttheordercancontainmultipleorderitems.Now,foreachorderitem,weneedtodoaseparateinventorycheck.Tosolvethisproblem,wecanroutetheordertoanXPathsplitterfirst.Thesplittercansplittheorderintoindividualorderitemsandeachorderitemcanbepushedtothequeueasaseparatemessage.Nowitiseasytoplug-inacontent-basedrouteraswehavediscussedalready.Theneachnewmessageencapsulatingoneorderitemcanberoutedtotheirrespectiveinventoryqueues.
SAMPLEUSECASEThesampleusecasewillhavethefollowingcomponents:
JMSclient:ThisisanormalexternalJMSclient,placingtheXMLcompositemessagesontotheJMSconsumercomponentconfiguredwithintheESB.
JMSconsumer:Thisisaservicemix-jmslisteningonqueue"A".AnyincomingmessagestothisqueuewillberoutedtothenextcomponentintheflowchainwhichistheXPathsplitter.
XPathsplitter:TheXPathsplitterisaservicemix-eipcomponent.Onreceivingtheinmessages,thesplitterwilltrytomatchtheXPathconfiguredatthesplitter-levelwiththemessagecontent.Infindingamatch,thesplitterwillsplittheoriginalmessageintoasmanypartsastherearerepeatingelementsaspertheXPath.Eachoftheseindividualelementsisrepublishedasaseparatemessagetotheexchange-targetwhichisatracecomponent.
Tracecomponent:Thetracecomponentjustspitsoutwhatevermessageitreceivesintotheconsole.
Thefollowingfigureillustrateshowthevariouscomponents
canbeassembledintheJBIbusforoursampleusecase:
SAMPLECODEANDCONFIGURATIONWeconfiguretheXPathsplitterinservicemix.xml,alongwithothercomponentsdescribedabove:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns="http://xbean.org/schemas/spring/1.0"
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:test="http://xslt.servicemix.apache.binildas.com"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0">
<classpath>
<location>.</location>
</classpath>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml"/>
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<sm:containername="jbi"
monitorInstallationDirectory="false"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpec>
<sm:component>
<jms:component>
<jms:endpoints>
<jms:endpointservice="test:MyConsumerService"
endpoint="myConsumer"role="consumer"
soap="false"targetService="test:xpathSplitter"
defaultMep="http://www.w3.org/2004/
08/wsdl/in-only"destinationStyle="queue"
jmsProviderDestinationName="queue/A"
connectionFactory="#connectionFactory">
<jms:endpoints>
</jms:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpecid="servicemix-eip">
<sm:component>
<eip:component>
<eip:endpoints>
<eip:xpath-splitterservice="test:xpathSplitter"
endpoint="xpathSplitterEndpoint"xpath="hello*">
<eip:target>
<eip:exchange-targetservice="my:trace">
<eip:target>
</eip:xpath-splitter>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="trace"
service="my:trace">
<sm:component>
<beanclass="org.apache.servicemix.components.
util.TraceComponent">
<sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
<beanid="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<propertyname="brokerURL"
value="tcp://localhost:61616">
<bean>
</beans>
TheXPathweconfiguredhereishello*.Thiswillspliteachelementinsidethehelloelementintoindividualmessages.
DEPLOYANDRUNTHESAMPLETobuildthesample,changedirectorytoch15\03_XPathSplitterandtypeantasgivenhere:
cdch15\03_XPathSplitter
ant
Thiswillcompileallthefiles,includingtheJMSclient
program.Nowtotestthesample,firstbringServiceMixupbyexecutingthefollowingcommands:
cdch15\03_XPathSplitter
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
Nowinadifferentcommandpromptexecuteantrunasshownhere:
cdch15\03_XPathSplitter
antrun
TheJMSclientprogramconsolewillprintoutthemessagesitsendstotheESBasshowninthefollowingscreenshot:
NowontheESB-side,thefirstmessagewillbesplitintothreepartswhereasthelast(third)messagewillbesplitintotwoparts.
INFO-TraceComponent
-Bodyis:<?xmlversion="1.0"
encoding="UTF-8"?><one/>
INFO-TraceComponent
-Bodyis:<?xmlversion="1.0"
encoding="UTF-8"?><three/>
INFO-TraceComponent
-Bodyis:<?xmlversion="1.0"
encoding="UTF-8"?><two/>
INFO-TraceComponent
-Bodyis:<?xmlversion="1.0"
encoding="UTF-8"?><five/>
INFO-TraceComponent
-Bodyis:<?xmlversion="1.0"
encoding="UTF-8"?><four/>
StaticRecipientListArecipientlistcaninspectanincomingmessage,anddependinguponthenumberofrecipientsspecifiedintherecipientlist,itcanforwardthemessagetoallchannelsassociatedwiththerecipientsintherecipientlist.
NOTATION
EXPLANATIONTheexampleforascenariowhereweneedtosendthesamemessagetomultiplerecipientsistheemailmessage.Witheveryemailmessage,thesendercanspecifymultiple
recipientsintheTo,Cc,orBccfields.Now,theemailsystemcaninspectthesefieldsandifmorethanonerecipientisspecifiedintheselists,itwillforwardthesamemessagetoalltherecipientaddressesspecified.
ILLUSTRATIVEDESIGNWhenevertheAcmeback-endsystemreceivesaconfirmedorder,thesamehastobedistributedtobothpackingsystemsandshippingsystems,alongwiththeinventorysystemswhichwehavealreadydiscussed.Wecanconfigureastaticrecipientlistspecifyingashippingqueue,apackingqueue,andathirdqueueforacontent-basedrouterforinventorysystemsasshowninthefollowingfigure.TheadvantageisthatalltheseLOBsystemswillreceivethesameordersothattheycaninitiatetheirassociatedbusinessprocesses.Thisisillustratedinthefollowingfigure:
SAMPLEUSECASEThesampleusecasewillhavefollowingcomponents:
JMSclient:ThisisanormalexternalJMSclient,placingXMLcompositemessagesontotheJMSconsumercomponentconfiguredwithintheESB.
JMSconsumer:Thisisaservicemix-jmslisteningonqueue"A"'.AnyincomingmessagestothisqueuewillberoutedtothenextcomponentintheflowchainwhichistheStaticRecipientList.
Staticrecipientlist:TheStaticRecipientListisaservicemix-eipcomponent.Onreceivinginmessages,theStaticRecipientListwillforwardthemessagetoallrecipients,whicharedifferentinstancesofreceivercomponents,configuredintheStaticRecipientList.
Receivercomponent:Thereceivercomponentjustspitsoutwhatevermessageitreceivesintotheconsole.
ThefollowingfigureillustrateshowthevariouscomponentscanbeassembledintheJBIbusforoursampleusecase:
SAMPLECODEANDCONFIGURATIONWeconfiguretheStaticRecipientListinservicemix.xml,alongwiththeothercomponentsdescribedabove.Theservicemix.xmlfileisshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns="http://xbean.org/schemas/spring/1.0"
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:test="http://xslt.servicemix.apache.binildas.com"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0">
<classpath>
<location>.</location>
</classpath>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml"/>
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<sm:containername="jbi"
monitorInstallationDirectory="false"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpec>
<sm:component>
<jms:component>
<jms:endpoints>
<jms:endpointservice="test:MyConsumerService"
endpoint="myConsumer"role="consumer"
soap="false"targetService="test:recipients"
defaultMep="http://www.w3.org/2004/
08/wsdl/in-only"destinationStyle="queue"
jmsProviderDestinationName="queue/A"
connectionFactory="#connectionFactory">
<jms:endpoints>
</jms:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpecid="servicemix-eip">
<sm:component>
<eip:component>
<eip:endpoints>
<eip:static-recipient-list
service="test:recipients"endpoint="endpoint">
<eip:recipients>
<eip:exchange-targetservice="test:receiver1">
<eip:exchange-targetservice="test:receiver2">
<eip:exchange-targetservice="test:receiver3">
<eip:recipients>
</eip:static-recipient-list>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver1"
service="test:receiver1">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>1</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver2"
service="test:receiver2">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>2</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver3"
service="test:receiver3">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>3</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
<beanid="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<propertyname="brokerURL"
value="tcp://localhost:61616">
<bean>
</beans>
Wehaveconfiguredthreerecipientsnamelytest:receiver1,test:receiver2,andtest:receiver3inthestaticrecipientlistabove.
DEPLOYANDRUNTHESAMPLETobuildthesample,changedirectorytoch15\04_StaticRecipientListandtypeantasshownhere:
cdch15\04_StaticRecipientList
ant
Thiswillcompileallthefiles,includingtheJMSclientprogram.Nowtotestthesample,first,bringServiceMixupbyexecutingthefollowingcommands:
cdch15\04_StaticRecipientList
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
Nowinadifferentcommandpromptexecuteantrun.
cdch15\04_StaticRecipientList
antrun
TheJMSclientprogramconsolewillprintoutthemessagesitsendstotheESBasshowninthefollowingscreenshot:
Atthesametime,ifyouobservetheESBconsole,youcanseethemessageisdeliveredtoallthethreerecipientsintherecipientlist.
Wiretap
Thewiretapisakindofsimplerecipientlistwhich,wheninsertedintothemessagechannel,willpublisheachincomingmessageintothemainchannelaswellasintoasecondarychannel.
NOTATION
EXPLANATIONThewiretapisastaticrecipientlist,withonlytworecipientsinthelist.Wheninsertedintothemainchannel,itpublishestheinputmessageintothemainchannelaswellasthesecondarychannelconfiguredinthewiretap.Thewiretapwillnotmodifythemessagecontentsinanymanner.
ILLUSTRATIVEDESIGNSupposeyouwanttodoanauditforeverycreditcardpaymentthatyoumakethroughyourAcmeonlinestore.Yourcreditcardinformationwillreachtheback-endsystemandtherewecanuseawiretap.Hencethismessageisalsopublishedintoasecondaryauditmodulewhichwillwriteallrequiredinformationtoanon-erasabledisk.
SAMPLEUSECASEThesampleusecasewillhavethefollowingcomponents:
HTTPclient:ThisisanexternalHTTPclient,placingtheXMLmessagesontotheHTTPconnectorcomponentconfiguredwithintheESB.
HTTPconnector:ThisisaServiceMixHTTPcomponentlisteningonport8912.Anyincomingmessagestothisqueuewillberoutedtothenextcomponentintheflowchainwhichisthewiretap.
Wiretap:Thewiretapisaservicemix-eipcomponent.Onreceivinginmessages,thewiretapwillforwardthemessagetothemaintarget(anEchocomponentinourcase)aswellastothelistener(aTracecomponenthere).WiretapcanhandleallfourstandardMEPs,butcanonlysendanIn-OnlyMEPtothelistener.
Echocomponent:TheechocomponentisthemaintargetofthewiretapandwilltakepartinanIn-OutMEPintheflow.Hencetherequestisechoedbacktothewiretapandthentotheconsumercomponentofthewiretap(HTTPconnector).
Tracecomponent:TheTracecomponenttakespartinanIn-OnlyMEPintheflowandwillprintthemessageintheconsole.
ThefollowingfigureillustrateshowthevariouscomponentscanbeassembledintheJBIbusforoursampleusecase:
SAMPLECODEANDCONFIGURATIONWeconfigurethewiretapintheservicemix.xmlfile,alongwithothercomponentsdescribedabove.Thisfileisreproducedinthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns="http://xbean.org/schemas/spring/1.0"
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:test="http://xslt.servicemix.apache.binildas.com"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0">
<classpath>
<location>.</location>
</classpath>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml"/>
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.
config.PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<sm:containername="jbi"
monitorInstallationDirectory="false"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpeccomponentName="httpReceiver"
service="test:httpBinding"
endpoint="httpReceiver"
destinationService="test:wireTap">
<sm:component>
<beanclass="org.apache.servicemix.
components.http.HttpConnector">
<propertyname="host"value="localhost"/>
<propertyname="port"value="8912">
<bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="echo"
service="test:echo">
<sm:component>
<beanclass="org.apache.servicemix.
components.util.EchoComponent">
<sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="trace"
service="test:trace">
<sm:component>
<beanclass="org.apache.servicemix.components.
util.TraceComponent">
<sm:component>
</sm:activationSpec>
<sm:activationSpecid="servicemix-eip">
<sm:component>
<eip:component>
<eip:endpoints>
<eip:wiretapservice="test:wireTap"
endpoint="wireTapEndpoint">
<eip:target>
<eip:exchange-targetservice="test:echo">
<eip:target>
<eip:inListener>
<eip:exchange-targetservice="test:trace">
<eip:inListener>
</eip:wiretap>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
</beans>
Wehaveconfiguredbothtest:echoandtest:traceasthelistenersforthemessageexchangeinthewiretap.Hencethemessagewillbeforwardedtoboththesecomponents.
DEPLOYANDRUNTHESAMPLETobuildthesample,changedirectorytoch15\05_WireTapandtypeant:
cdch15\05_WireTap
ant
Thiswillcompileallthefiles,includingtheHTTPclient
program.Nowtotestthesample,firstbringServiceMixupbyexecuting:
cdch15\05_WireTap
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
Nowinadifferentcommandpromptexecuteantrun.
cdch15\05_WireTap
antrun
TheHTTPclientprogramwillsendthetestXMLmessagetotheHTTPconnectorconfiguredintheESB.IntheESBconsolewecanvalidatethatthemessageisdeliveredtoboththetest:echoandtest:traceservices.TheHTTPclientalsoprintsouttheresponsereceivedbackfromtheESB.
MessageFilterMessagefiltercaneliminatetheunwantedmessagesfromasetofmessagespublished.
NOTATION
EXPLANATION
Messagesareofdifferentkinds,andthesameistruewitheventsalso.Thereareunwantedeventsandeventswhicharetobetrackedandreactedbasedoneventtypeinparticularfashions.Whetheramessageisofinterestornotisagainbasedonthemessagecontent.Hencethemessageswhichmatchthefilterruleofinterestneedtoberoutedfurtherwhereasthemessageswhichdidn'tmatchthefiltercriterionareignored.Allthemessageswhichmatchthecriterionwillberoutedtotheoutputchannelofthemessagefilter.
ILLUSTRATIVEDESIGNAcmehasdecidedtoofferdiscountsandgiftsforallpurchasesexceedingacertainamountinasinglecheckout.Toprocessthis,wecanfirstuseawiretaptosendacopyofallorderstoamessagefilter.Themessagefilterwillinspectthemessageforthetotaldollarvalueofcheckoutandifitexceedsthethreshold,themessagewillbeforwardedtotheoffermanagementmodule.Anyordermessageswithtotaldollarvaluelessthanthethresholdwillbeignored(dropped)atthemessagefilter,notforwardingthemtotheoffermanagementmodule.Notethat,wearedirectingcopiesofordersonlytothemessagefilterhencealltheoriginalmessageswillberoutedtotheirrespectiveinventorymodules,irrespectiveofwhethertheircopiesareforwardedordroppedatthemessagefilter.Thisisillustratedinthefollowingfigure:
SAMPLEUSECASEThesampleusecasewillhavefollowingcomponents:
JMSclient:ThisisanormalexternalJMSclient,placingXMLmessagesontotheJMSconsumercomponentconfiguredwithintheESB.
JMSconsumer:Thisisaservicemix-jmslisteningonqueue"A".AnyincomingmessagestothisqueuewillberoutedtothenextcomponentintheflowchainwhichistheMessageFilter.
Messagefilter:TheMessageFilterisaservicemix-eipcomponent.Onreceivingtheinmessages,thefilterwilltrytomatchthefilterruleconfiguredatthefilter-levelwiththemessagecontent.Inthesample,weusetheXPathpredicatetodefinethefilterrule.Infindingamatch,thefilterwillforwardthemessagetotheexchange-targetwhichisareceivercomponent.Anymessagewhichdoesn'tmatchwillbedroppedatthefilter-level.
Receivercomponent:Thereceivercomponentjustspitsoutwhatevermessageitreceivesintotheconsole.
ThefollowingfigureillustrateshowthevariouscomponentscanbeassembledintheJBIbusforoursampleusecase:
SAMPLECODEANDCONFIGURATIONWeconfiguretheMessageFilterintheservicemix.xmlfile,alongwithothercomponentsdescribedabove.Thisisshowninthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns="http://xbean.org/schemas/spring/1.0"
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:test="http://xslt.servicemix.apache.binildas.com"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0">
<classpath>
<location>.</location>
</classpath>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml"/>
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<sm:containername="jbi"
monitorInstallationDirectory="false"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpec>
<sm:component>
<jms:component>
<jms:endpoints>
<jms:endpointservice="test:MyConsumerService"
endpoint="myConsumer"role="consumer"
soap="false"targetService="test:messageFilter"
defaultMep="http://www.w3.org/2004/
08/wsdl/in-only"destinationStyle="queue"
jmsProviderDestinationName="queue/A"
connectionFactory="#connectionFactory">
<jms:endpoints>
</jms:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver"
service="test:receiver">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>1</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpecid="servicemix-eip">
<sm:component>
<eip:component>
<eip:endpoints>
<eip:message-filterservice="test:messageFilter"
endpoint="messageFilterEndpoint">
<eip:target>
<eip:exchange-targetservice="test:receiver">
<eip:target>
<eip:filter>
<eip:xpath-predicate
xpath="hello@id='1'">
<eip:filter>
</eip:message-filter>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
<beanid="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<propertyname="brokerURL"
value="tcp://localhost:61616">
<bean>
</beans>
ThefilterrulewearespecifyinghereistheXPath"hello@id='1'".ThecodeforMyReceiver.javaclassisverysimilartotheMyReceiverusedinthecontent-basedroutersample.Theonlydifferenceisthatitwon'twriteanycontentbacktotheout.Hencewearenotrepeatingthecodehere.
DEPLOYANDRUNTHESAMPLETobuildthesample,changedirectorytoch15\06_MessageFilterandtypeantasshownhere:
cdch15\06_MessageFilter
ant
Thiswillcompileallthefiles,includingtheJMSclientprogram.Nowtotestthesample,first,bringServiceMixupbyexecuting:
cdch15\06_MessageFilter
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
Nowinadifferentcommandpromptexecuteantrun.
cdch15\06_MessageFilter
antrun
TheJMSclientprogramconsolewillprintoutthemessagesitsendstotheESBasshowninthefollowingfigure:
IfwelookattheESBconsole,wecanseethatonlytwoofthemessagesarefilteredandforwardedtothereceivercomponentandtheothertwomessagesaredropped.
SplitAggregatorAnaggregatorisakindofstatefulfilterwhichcanstoremessagepartswhicharecorrelatedbysomeformofIDorfield.Whenallthepartsarereadyitcanaggregatealltheparts
andpublishasingleaggregatemessage.
NOTATION
EXPLANATIONInmanycasesmessagepartswhichareco-relatedarriveatdifferenttimesandwecannotproceedfurtherprocessingunlesswereceivethemessageinfull.Thescenarioiscommonintheairlinedomainwherethemessagingchannelsplitsandsendspassengerreservationlistsandpassengernamelistsinparts,duetosizelimitationsimposedbyEDImessaginggateways.Theprocessingmodulehastowaituntilitreceivesallthepartsofaco-relatedmessage.Tohelpthecorrectorderingofmessagesbackandtoidentifywhetherwehavereceivedallpartsofthemessage,theaggregatordependsonseveralpropertiessuchascount,index,andcorrelationID.Eachintermittentresultisstoredbytheaggregatoruntilthemessageisfullyaggregated.Hencetheaggregatorisstatefulinnature.
ILLUSTRATIVEDESIGNEveryfullorderintheAcmeback-endsystemhastobevalidatedwithanavailablestockbeforewecanconfirmtheorder.Wealreadydiscussedthatwesplittheorderintoorderitemsandsendindividualmessagescorrespondingtoeach
itemtodifferentinventorymodules.Now,beforewecanreturnbacktheordervalidationmessagetothecustomerweneedtoexaminethevalidationstatusofeachorderitemfromtheinventorymodules.Onepossibleconfigurationistouseanaggregatortowhichalltheinventorymodulescanroutetheindividualorderitemstatusmessages.Theaggregator,whenitreceivesthestatusmessagesfromalltherelatedorderitems,canevaluatetheoverallstatusandsendbackthedecision(confirmedorderorerror).Thisisshowninthefollowingfigure:
SAMPLEUSECASEThesampleusecasewillhavethefollowingcomponents:
DefaultServiceMixclient:ThedefaultServiceMixclientwillsendseveralIn-OnlymessagestothesplitaggregatorconfiguredintheESB.Eachofthesemessagesiscorrelated,andtheyalsocarrythesplitCountandsplitIndexalongwiththeirmessageproperties.
Splitaggregator:Thesplitaggregatorisaservicemix-eipcomponent.
Onreceivingtheinmessages,theaggregatorwilllookatthecorrelationID,splitCount,andsplitIndexandcanrearrangeandaggregatethemessagesirrespectiveoftheorderinwhichthemessagesarrive.Wheneverypartofamessagehasarrived,thefullyaggregatedmessageisforwardedtothenextcomponentintheflowchainwhichisthetracecomponent.
Tracecomponent:ThetracecomponentprintsouttheaggregatedmessagesreceivedfromthesplitaggregatortotheESBconsole.
ThefollowingfigureillustrateshowthevariouscomponentscanbeassembledintheJBIbusforoursampleusecase:
SAMPLECODEANDCONFIGURATIONWeconfiguretheSplitAggregatorintheservicemix.xml
file,alongwithothercomponentsdescribedabove.
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns="http://xbean.org/schemas/spring/1.0"
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:test="http://xslt.servicemix.apache.binildas.com"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0">
<classpath>
<location>.</location>
</classpath>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml"/>
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<sm:containerid="jbi"
monitorInstallationDirectory="false"
createMBeanServer="false"useMBeanServer="false">
<sm:activationSpecs>
<sm:activationSpecid="servicemix-eip">
<sm:component>
<eip:component>
<eip:endpoints>
<eip:split-aggregatorservice="test:aggregator"
endpoint="aggregatorEndpoint"
aggregateElementName="test:MessageEnvelope"
messageElementName="test:MessagePart">
<eip:target>
<eip:exchange-targetservice="test:trace">
<eip:target>
</eip:split-aggregator>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="trace"
service="test:trace">
<sm:component>
<beanclass="org.apache.servicemix.components.
util.TraceComponent">
<sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
<beanid="client"
class="org.apache.servicemix.client.
DefaultServiceMixClient">
<constructor-argref="jbi">
<bean>
</beans>
ThesplitaggregatorisconfiguredwiththeelementsaggregateElementNameandmessageElementName.Thesetwoelementswilldecidethemessageenvelopestobeusedwhenthesplitaggregatoraggregatesthemessage.
DEPLOYANDRUNTHESAMPLETobuildthesample,changedirectorytoch15\07_SplitAggregatorandtypeantasshownhere:
cdch15\07_SplitAggregator
ant
Thiswillcompileallthefiles.Nowtotestthesample,justexecutetheruntargetofbuild.xmlasshownasfollows:
cdch15\07_SplitAggregator
antrun
ObservetheESBconsole;youcanseethemessagesbeingsentouttotheaggregatorandfinallytheaggregatorcombinesallrelatedmessagesandforwardsthemtothetracecomponentwhichwillprintoutthemessagetotheconsole.Thisisshownasfollows:
Sendmsg:corrId<1178104210727>:
splitterCount<3>:splitterIndex<1>:msg<<hello
id="1"><binil/><sowmya/></hello>>
Waiting5000millisbeforenextmessage...
Sendmsg:corrId<1178104215726>:
splitterCount<2>:splitterIndex<1>:msg<<hello
id="1"><ann/></hello>>
Waiting5000millisbeforenextmessage...
Sendmsg:corrId<1178104210727>:
splitterCount<3>:splitterIndex<0>:msg<<hello
id="0"><binil/><sowmya/></hello>>
Waiting5000millisbeforenextmessage...
Sendmsg:corrId<1178104215726>:
splitterCount<2>:splitterIndex<0>:msg<<hello
id="0"><ann/></hello>>
Waiting5000millisbeforenextmessage...
INFO-TraceComponent-Exchange:InOnly[
id:ID:10.10.10.10-1124c7badc9-2:0
status:Active
role:provider
service:
{http://xslt.servicemix.apache.binildas.com}trace
endpoint:trace
in:<?xmlversion="1.0"encoding="UTF-8"?>
<test:MessageEnvelope
<test:MessageEnvelope
xmlns:test="http://xslt.servicemix.apache.binildas.com"
count="2"><test:MessagePartindex="0"><hello
id="0"><ann/></hello></test:MessagePart>
<test:MessagePartindex="1"><helloid="1"><ann/>
</hello></test:MessagePart>
</test:MessageEnvelope>
]receivedINmessage:
org.apache.servicemix.jbi.messaging.NormalizedMessageImpl@199197b{properties:
{org.apache.servicemix.eip.splitter.corrid=1178104215726}}
INFO-TraceComponent-Bodyis:<?xml
version="1.0"
encoding="UTF-8"?><test:MessageEnvelope
xmlns:test="http://xslt.servicemix.apache.binildas.com"
count="2"><test:MessagePartindex="0"><hello
id="0"><ann/></hello></test:MessagePart>
<test:MessagePartindex="1"><helloid="1"><ann/>
</hello></test:MessagePart>
</test:MessageEnvelope>
Sendmsg:corrId<1178104210727>:
splitterCount<3>:splitterIndex<2>:msg<<hello
id="2"><binil/><sowmya/></hello>>
Waiting5000millisbeforenextmessage...
INFO-TraceComponent-Exchange:InOnly[
id:ID:10.10.10.10-1124c7badc9-2:1
status:Active
role:provider
service:
{http://xslt.servicemix.apache.binildas.com}trace
endpoint:trace
in:<?xmlversion="1.0"encoding="UTF-8"?>
<test:MessageEnvelope
xmlns:test="http://xslt.servicemix.apache.binildas.com"
count="3"><test:MessagePartindex="0"><hello
id="0"><binil/><sowmya/></hello>
</test:MessagePart><test:MessagePartindex="1">
<helloid="1"><binil/><sowmya/></hello>
</test:MessagePart><test:MessagePartindex="2">
<helloid="2"><binil/><sowmya/></hello>
</test:MessagePart></test:MessageEnvelope>
]receivedINmessage:
org.apache.servicemix.jbi.messaging.NormalizedMessageImpl@195ff24{properties:
{org.apache.servicemix.eip.splitter.corrid=1178104210727}}
INFO-TraceComponent-Bodyis:<?xml
version="1.0"encoding="UTF-8"?>
<test:MessageEnvelope
xmlns:test="http://xslt.servicemix.apache.binildas.com"
count="3"><test:MessagePartindex="0"><hello
id="0"><binil/><sowmya/></hello>
</test:MessagePart><test:MessagePartindex="1">
<helloid="1"><binil/><sowmya/></hello>
</test:MessagePart><test:MessagePartindex="2">
<helloid="2"><binil/><sowmya/></hello>
</test:MessagePart></test:MessageEnvelope>
PipelineAPipelineisakindofbridgewhichcantransformoneformofMEPtoanother.
NOTATION
Forapipeline,thereisnonotationprovidedintheEAIpatternscollection.HencethebridgeEAIpatternisextendedandshownhere.Themotivationbehinddoingsoisthatitispossibletobuildabridgebetweentwomessageexchangepatternsusingapipeline.
EXPLANATIONApipelinecanbeconfiguredtotransformanIn-OnlyMEPtoanIn-Out.Thatis,whenthepipelinereceivesanIn-OnlyMEP,itsendsthemessageinanIn-OutMEPtothetransformercomponent.Hence,thetransformerwillsendaresponseasanoutmessagefortheIn-Out.ThisoutmessageisthenforwardedtothepipelinetargetinanotherIn-OnlyMEP.
UsingtheMEPtransformationpropertyofpipeline,itispossibletoconstructaprotocolbridge.Forexample,wecanbridgebetweenaHTTPprotocol(In-Out)andaJMS(In-Only)protocol.ThisiswhatwehavedoneinChapter11(AccessWebServicesusingJMSChannel).
ILLUSTRATIVEDESIGNTheAcmee-commercesystemallowscustomersonlinetomakepaymentsandeachsuchpaymentmessageisroutedtothefinancialinstitution'ssysteminasecureandreliablemanner.ThefinancialinstitutionisAcme'spaymentpartnerandtheirsystemsareseparatedinadifferentnetworkanddomain.SendingrequeststhroughInternetisafeasiblemethod,buttheusualHTTPchanneldoesnothavetherequiredreliability.HencethereisadedicatednetworkbetweenAcmeandthefinancialinstitution.Moreover,tomakemessagingreliableitispossibletosendmessagesusingareliablechannelthroughMOM.UsingJMS,wecansendmessagesthroughMOM.However,thepaymentserviceatthefinancialinstitution'sendisaHTTPservicewitharequest-replystyle.HencetheIn-OnlyMEPusedinJMSdoesn'tfit
well.Apipelinecansolvethisproblembyprovidingabridgebetweenthetwoprotocols—JMSandHTTP.Thisdesignisshowninthefollowingfigure:
YoumayalsorefertheChapter11(AccessWebServiceusingJMSChannel)toseeanimplementationforthis.
SAMPLEUSECASEThesampleusecasewillhavethefollowingcomponents:
JMSclient:ThisisanormalexternalJMSclient,placingXMLmessagesontotheJMSconsumercomponentconfiguredwithintheESB.
JMSconsumer:Thisisaservicemix-jmslisteningonqueue"A".Anyincomingmessagestothisqueuewillberoutedtothenextcomponentintheflowchainwhichisthepipeline.
Pipeline:ThePipelineisaservicemix-eipcomponent.ThepipelinereceivesanIn-OnlyMEPfromJMSconsumer.ThepipelinethensendsthesamemessageinanIn-OutMEPtotheechocomponent.TheechoedresponseissendbacktothepipelinewhichisthenforwardedtotheJMSconsumerinanotherIn-OnlyMEP.
Echocomponent:Theechocomponentechoesbackanymessagesitreceives.Themessagereceivedfromthepipelineisthussentbacktothepipeline.
JMSprovider:Thisisaservicemix-jmslisteningonqueue"B".ThepipelinewillplacetheechoedbackmessageintothisqueueinanIn-OnlyMEPfromwheretheJMSclientcanpickup.
ThefollowingfigureillustrateshowthevariouscomponentscanbeassembledintheJBIbusforoursampleusecase:
SAMPLECODEANDCONFIGURATIONWeconfigurethepipelineintheservicemix.xmlfile,alongwithothercomponentsdescribedabove.Thecontentofthisfileisshownhere:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns="http://xbean.org/schemas/spring/1.0"
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:test="http://xslt.servicemix.apache.binildas.com"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0">
<classpath>
<location>.</location>
</classpath>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml"/>
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<sm:containername="jbi"
monitorInstallationDirectory="false"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpec>
<sm:component>
<jms:component>
<jms:endpoints>
<jms:endpointservice="test:MyConsumerService"
endpoint="myConsumer"role="consumer"
soap="false"targetService="test:pipeline"
defaultMep="http://www.w3.org/2004/
08/wsdl/in-only"destinationStyle="queue"
jmsProviderDestinationName="queue/A"
connectionFactory="#connectionFactory">
<jms:endpointservice="test:MyProviderService"
endpoint="myProvider"role="provider"
soap="false"destinationStyle="queue"
jmsProviderDestinationName="queueB"
connectionFactory="#connectionFactory">
<jms:endpoints>
</jms:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="echo"
service="test:echo">
<sm:component>
<beanclass="org.apache.servicemix.components.
util.EchoComponent">
<sm:component>
</sm:activationSpec>
<sm:activationSpecid="servicemix-eip">
<sm:component>
<eip:component>
<eip:endpoints>
<eip:pipelineservice="test:pipeline"
endpoint="pipelineEndpoint">
<eip:transformer>
<eip:exchange-targetservice="test:echo">
<eip:transformer>
<eip:target>
<eip:exchange-target
service="test:MyProviderService">
<eip:target>
</eip:pipeline>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
<beanid="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<propertyname="brokerURL"
value="tcp://localhost:61616">
<bean>
</beans>
DEPLOYANDRUNTHESAMPLETobuildthesample,changedirectorytoch15\08_Pipelineandtypeantasshownhere:
cdch15\08_Pipeline
ant
Thiswillcompileallthefiles,includingtheJMSclientprogram.Nowtotestthesample,firstbringServiceMixupbyexecuting:
cdch15\08_Pipeline
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
Nowinadifferentcommandpromptexecuteantrunasshownhere:
cdch15\08_Pipeline
antrun
Theoutputfortheabovecommandisshowninthefollowingscreenshot:
Asseeninthefigure,therequestandresponsemessagewillpassthroughthepipelinewhichwillbridgethetwoIn-OnlyMEPexchanges(requestandresponse)toanIn-OutMEPexchange(Echocomponent).
StaticRoutingSlipAstaticroutingslipcanrouteamessagecominginanIn-OutMEPthroughaseriesofconfiguredtargetservices.
NOTATION
EXPLANATIONYoumightbeawareoftheservletfilters,whichisakindofpipeandfilterconfigurationtodoprocessingatthepresentationtier.Sometimeswemayneedtodosimilar
processing,throughaseriesofprocessblocks.Theexactprocessingblocksthroughwhichthemessagehastoberoutedcanbedynamicbasedonthetypeofmessage.Inastaticroutingslip,theseprocessingblocksortargetservicesarefixed.TheServiceMixroutingslipusesIn-OutMEPsanderrorsorfaultssentbythetargetsarereportedbacktotheconsumer.Incaseoferrorstheroutingprocessisinterrupted.
ILLUSTRATIVEDESIGNWhentheAcmecustomerdropsitemsintotheshoppingcart,wemayalsoneedtoextendanyoffersordiscountsassociatedwiththeselecteditem.Thishastobedoneaftertheinitialinventorycheck.Wecanattacharoutingsliptoeachmessagesothatthemessagesareroutedinseriesthroughtheinventorymoduleandtheoffermodule.Thisisexplainedinthefollowingfigure:
SAMPLEUSECASEThesampleusecasewillhavefollowingcomponents:
HTTPclient:ThisisanexternalHTTPclient,placingtheXMLmessagesontotheHTTPconnectorcomponentconfiguredwithintheESB.
HTTPconnector:ThisisaServiceMixHTTPcomponentlisteningonport8912.AnyincomingmessagestothisqueuewillberoutedtothenextcomponentintheflowchainwhichistheStaticRoutingSlip.
Staticroutingslip:TheStaticRoutingSlipisaservicemix-eipcomponent.Onreceivinginmessages,theStaticRoutingSlipwillattachroutingslipswhicharepre-configuredtothemessage.NowtheESBcanroutethemessageinseriesthroughtheservicesspecifiedthroughtheslips.
Receivercomponent:MultipleinstancesofthereceivercomponentareconfiguredintheESB.Theroutingslipattachesslipscorrespondingtoonlyafewofthereceiverswitheveryincomingmessage.Hencethemessagesareforwardedthroughthesereceiverinstancesonly,othersareneglected.
Oncompletingtheflow,theHTTPclientcanretrievebackthemessagefromtheHTTPconnectorasshowninthefollowingfigure:
SAMPLECODEANDCONFIGURATIONWeconfigurethepipelineintheservicemix.xmlfile,alongwithothercomponentsdescribedabove.
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns="http://xbean.org/schemas/spring/1.0"
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:test="http://xslt.servicemix.apache.binildas.com"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0">
<classpath>
<location>.</location>
</classpath>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml"/>
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<sm:containername="jbi"
monitorInstallationDirectory="false"
createMBeanServer="true"useMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpeccomponentName="httpReceiver"
service="test:httpBinding"
endpoint="httpReceiver"
destinationService="test:routingSlip">
<sm:component>
<beanclass="org.apache.servicemix.components.
http.HttpConnector">
<propertyname="host"value="localhost"/>
<propertyname="port"value="8912">
<bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver1"
service="test:receiver1">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>1</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver2"
service="test:receiver2">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>2</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver3"
service="test:receiver3">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="MyReceiver">
<propertyname="name">
<value>3</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpecid="servicemix-eip">
<sm:component>
<eip:component>
<eip:endpoints>
<eip:static-routing-slip
service="test:routingSlip"
endpoint="routingSlipEndpoint">
<eip:targets>
<eip:exchange-targetservice="test:receiver1"/>
<eip:exchange-targetservice="test:receiver3">
<eip:targets>
</eip:static-routing-slip>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
</beans>
DEPLOYANDRUNTHESAMPLETobuildthesample,changedirectorytoch15\09_StaticRoutingSlipandtypeantasshownhere:
cdch15\09_StaticRoutingSlip
ant
Thiswillcompileallthefiles,includingtheJMSclientprogram.Nowtotestthesample,firstbringServiceMixupbyexecuting:
cdch15\09_StaticRoutingSlip
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
Nowinadifferentcommandpromptexecuteantrun.
cdch15\09_StaticRoutingSlip
antrun
Theoutputfortheabovecommandisshowninthefollowingscreenshot:
IfyouobservetheESBconsoleyoucanseethattheESBroutesthemessageinseriesthroughtheservicesspecifiedthroughtheslips(test:receiver1andtest:receiver3).
SummaryIntegrationrequiresalevelofthinkingdifferentfromthetraditionalsoftwareengineeringwhereyouhavetothinkintermsofsoftware"plugs"and"sockets".IhavetoadmitthatmyuniversitycoursesinMachineDesignhelpedmealottothinkofthesoftwareintegrationproblemintermsof"shafts"andcoupling"—infact,theircounterpartsinEAI.Ihopeyoutooadmitthatafterreadingthischapter.So,thenexttimewhenyouwanttointegratesoftwarecomponentsthinkintermsofEAIandpatterns.Moreover,tryto"selectandassembleintegrationbuildingblocks"ratherthanhandcodingandhardwiringendpoints.Thiswillhelpyoutointegrateinaloosely-coupledmannerwhichwillfacilitateeasyservice
collaborationandorchestration.ThenextchapterwillshowyouasampleofaggregatingmultipleservicesontheESBusingtheEAIpatternsandguidelineswhichwelearnedinthischapter.
Chapter16.SampleServiceAggregationInthepreviouschapterswecoveredmanyJBIcomponentsinServiceMixandalsosawafewusefulusecasestohelpsolvereallifeproblemsusingtheESBpatterns.AnotherusefulapplicationofESBistoprovidea"ServicesWorkbench"whereinwecanusevariousintegrationpatternsavailabletoaggregateservicestocarryoutbusinessprocesses.Wewilllookintosuchasampleusecaseinthischapter.
Wewilllookatthefollowingtopicsinthebusinessintegrationsample:
Solutionarchitecture
JBI-basedESBcomponentarchitecture
Understandingthemessageexchange
Deployandrunthesample
ProvisionServiceOrder—BusinessIntegrationSampleTodemonstratetheserviceaggregation,wewillchooseatypicalbusinessintegrationscenariohappeningasanoutcomeofacustomerattemptingtomakeaweborderentry.Letus
takethescenarioofaCommunicationServiceProvider(CSP)providingawebaccesschannelforitscustomerstoorderVoiceoverIP(VOIP)service.
Wewillconsiderasingleprocessofordergeneration,whichisacoreprocessinanordermanagementsystem(OMS).Theordergenerationprocessacceptsandissuesorders.Thisprocesscanbedividedintostepssuchasorderentryandvalidation.Ifweconsiderasinglestepsuchasthevalidation,itcanbedecomposedintomultiplevalidationactivitiestobeperformedbymorethanonethird-partyserviceproviders.Thismakessenseintoday'sservice-orientedenvironment,whereservicesareprovidedbymultiplevendorsandasingleaggregateserviceiscomposedofmultipleline-itemservicesofferedbymultiplevendors.
Inourexamplescenario,letusconsiderthreevalidationservicestobedone:
Addressvalidation
Creditcardvalidation
Bankhistoryvalidation
Theabovefine-grainedservicesareofferedbydifferentthird-partyvendors.Hence,asperindustrystandards,thebestwaytoaccessthoseservicesisusingSOAPoverHTTP.TheAddressServicevalidatestheaddressenteredbytheuserandalsocheckstoseewhethertheVOIPservicecanbeprovidedintherequestedarea.CreditGatewayisacompositeservice,andthesuccessfuloperationofthisservicedependsupontheresponsesfromtwootherthird-partyvendorservicescalled
"CreditAgency"and"BankAgency".TheCreditAgencychecksforthecreditworthinessofthecustomer,andtheBankAgencychecksforthecustomer'sbankingtransactionhistory.
SolutionArchitectureLetusfirstlookatwhatJBI-basedtechnicalcomponentsarerequiredforframingoursolutionarchitecture.Thisisshowninthefollowingfigure:
Theabovefigureshowsthesolutionarchitectureforthebusinessscenariodescribedearlier.InordertoframetheESBsolutionarchitectureforthesamplescenario,wewillfirstlisttheindividualcomponentsrequired.IndividualESBcomponentsarechosenbasedonthetransportrequirementsto
facilitatetheinformationflow.Thesecomponentsareexplainedinthefollowinglist:
Endpoint:Anendpointconnectsservicesacrosssystems,applications,andenterprisestogether.Anendpointexposesstandardinterfacesandhidesalltransport-specificaspects,thusprovidinganabstractplug-inpoint.Theendpointsarerequiredforthesamplebusinessscenariotoaccesstheaddress,credit,andbankservice.
Translator:ThetranslatorsconvertbetweenmessageformatsandaresynonymouswiththeadapterpatternlistedintheGangofFourDesignPatternsbook.Inthesamplearchitecture,thevalidationbrokerserviceneedstotalktotheexternalservicesthroughtheSOAPprotocol.Hence,theJavaobjectsneedtobetranslatedtoXMLformat,andviceversa.
Normalizer:Thecreditandbankservicesdealwithmessagesthathavethesamemeaningbutdifferentformats.Thisisbecausedifferentexternalsystemshavetheirownmessageformats.Thismeansthemessagesareindifferentformats,butaresemanticallyequal.Anormalizerroutessemanticallyequalmessagestodifferentmessagetranslators.
Recipientlist:Inscenarioswhereweneedtoroutemessagetomultipleendpoints,wewillusearecipientlist.Therecipientscanbespecifieddynamicallyalso.Inourscenario,weneedtosendthesamemessagetoboththecreditandbankservices.Here,oncetheendpointsaredefined,therecipientlistwillforwardthemessagetoallchannelsassociatedwiththerecipientsinthelist.
Aggregator:AstheCreditGatewaydependsuponthecombinedoutcomeoftwootherservices(CreditAgencyandBankAgency),weneedtouseastatefulfiltertocollectandstoreindividualmessagesuntilacompletesetofrelatedmessageshasbeenreceived.Anaggregatordoesthisjobbycombiningtheresultsofindividual,butrelatedmessagessothattheycanbeprocessedasawhole.
JBI-basedESBComponentArchitectureThefollowingfigureshowsthevariousJBIcomponentswe
assembletodesigntheintegrationsolutionfortheordervalidationbusinessprocess.Thefunctionalityofthesecomponentsisalreadydiscussed.Weareshowingthemessageflowinthisdiagram.WewilldetailoutthemessageflowsinthenextsectionwiththehelpofaUMLdiagram.
UnderstandingtheMessageExchangeAsit'ssaidthatadiagramspeaksathousandwords,sodoestheUMLdiagramthatnarratescomplexmessageflowsinasimplemanner.Hence,letusunderstandthemessageexchangeswiththehelpofsequencediagrams.TheSequence1isshowninthefollowingfigure:
TheSequence1showsthemain"Controlflow",orchestratedbythebroker.ThecontrolcodeisprovidedwithintheonMessageExchangemethodinthebrokerandisreproducedinthefollowingcode:
publicclassSyncVoipBrokerextends
ComponentSupportimplements
MessageExchangeListener
{
{
privateMapaggregations=
Collections.synchronizedMap(newHashMap());
privateJBIContainercontainer;
privateStringname;
privateStringaddressNamespaceURI;
privateStringaddressLocalPart;
privateStringcreditGatewayNamespaceURI;
privateStringcreditGatewayLocalPart;
privateObjectpayLoad;
privatebooleancreditVetoed;
privatevolatileintstack=0;
publicvoidonMessageExchange(MessageExchange
exchange)throwsMessagingException
{
System.out.println("SyncVoipBroker.onMessageExchange.
ExchangeId:X:"+exchange.getExchangeId());
serviceaggregation,businessintegration
samplemessageexchange,sequence1ServiceEndpoint
serviceEndpoint=null;
if(exchange.getStatus()==ExchangeStatus.DONE)
{
System.out.println("SyncVoipBroker.onMessageExchange.
ExchangeStatus.DONE");
dispose();
return;
}
if(exchange.getStatus()==ExchangeStatus.ERROR)
{
System.out.println("SyncVoipBroker.onMessageExchange.
ExchangeStatus.ERROR");
return;
}
if(exchange.getRole()==Role.PROVIDER)
{
System.out.println("SyncVoipBroker.onMessageExchange.
Role.PROVIDER");
processInputRequest(exchange);
}
else
{
System.out.println("SyncVoipBroker.onMessageExchange.
System.out.println("SyncVoipBroker.onMessageExchange.
Role.CONSUMER");
serviceEndpoint=exchange.getEndpoint();
if
(serviceEndpoint.getServiceName().getLocalPart().
equals(addressLocalPart))
{
processAddressValidationResponse(exchange);
}
elseif
(serviceEndpoint.getServiceName().getLocalPart().
equals(creditGatewayLocalPart))
{
processCreditGatewayResponse(exchange);
}
else
{
processServiceRequest(exchange);
}
}
}
}
IftheExchangeStatusis"DONE"or"ERROR"fortheinitialMessageExchange,wesimplylogandreturn.Ifnot,thenthebrokercomponentcantakepartinthemessageexchangeintworolesnamelytheproviderortheconsumer.
Fortheconsumerrole,therearemultiplepathswhichwillbeexplainedlater.Butfortheproviderrole,thebrokertransferscontroltoSequence2listedinthefollowingfigure:
InthenormalflowwhenaclientsendsamessagetotheESB,theonMessageExchangemethodinthebrokerwillbeinvokedintheproviderrole.WelabelthismessageExchangeastheRootExchange(todifferentiatethisexchangefromothernestedexchanges,whichwillbedescribedshortly)andkeepapointerofthatinaMapforfuturereference.TheXMLpayloadwhichweretrievefromthenormalizedMessageisconvertedtoJavaobjectsusingtheXStreamJavaXMLbindingutilitiesandstoredforfuturereference.WethencreateanewInOutexchangewithaddressastheLocalPartandsendittothedeliveryChannel.Thefollowingcodesnippetdetailsoutthesesequenceofevents:
publicclassSyncVoipBrokerextends
publicclassSyncVoipBrokerextends
ComponentSupportimplements
MessageExchangeListener
{
privatevoidprocessInputRequest(MessageExchange
exchange)throwsMessagingException
{
NormalizedMessagecopyMessage=
exchange.createMessage();
NormalizedMessageinNormalizedMessage=
exchange.getMessage("in");
getMessageTransformer().transform(exchange,
inNormalizedMessage,copyMessage);
Sourcecontent=copyMessage.getContent();
StringcontentString=null;
if(contentinstanceofDOMSource)
{
contentString=XMLUtil.retreiveSoapContent(
((DOMSource)content).getNode());
payLoad=
XStreamUtil.xmlToObject(contentString);//Cacheit
}
CustomerTOcustomerTO=((ServiceParamTO)
payLoad).getCustomer();
AddressTOaddressTO=customerTO.getAddress();
StringxmlAddress=
XStreamUtil.objectToXml(addressTO);
SourceaddressSource=newStreamSource(new
ByteArrayInputStream(xmlAddress.getBytes()));
StringcorrelationId=null;
if(exchange.getStatus()==
ExchangeStatus.ACTIVE)
{
correlationId=exchange.getExchangeId();
aggregations.put(correlationId,exchange);
InOutinout=createInOutExchange(newQName(
addressNamespaceURI,addressLocalPart),null,
null);
inout.setProperty(Constants.CORRELATION_ID_KEY,
correlationId);
inout.setProperty(Constants.CORRELATION_ID_KEY,
correlationId);
correlationId);
NormalizedMessagemsg=inout.createMessage();
msg.setContent(addressSource);
inout.setInMessage(msg);
send(inout);
}
System.out.println("SyncVoipBroker.processInputRequest.
correlationId:"+correlationId);
}
}
NotethenewlycreatedmessageExchangewhichwillagaininvoketheonMessageExchangemethodoftheaddress(whichinturncallsthetransformmethodofAddress—Sequence3).WhentheAddressservicereturns,theonMessageExchangemethodinthebrokerwillbeinvokedagain,butthistimeintheconsumerrole—consumertotheaddress.ThisdifferenceissubtlebutimportantbecauseinanIn-Outexchange,itistheconsumerwhohastoendamessageexchangewitha"done"or"error"status.TheAddressserviceissimpleandisshowninSequence3.ThefollowingfigureshowstheSequence3UMLdiagram:
InAddressservice,wevalidatetheaddressandtheresultofthevalidationissetasapropertyinthe"out"messageoftheMessageExchange.Thisisshowninthefollowingcode:
publicclassAddressValidationServiceextends
TransformComponentSupport
{
protectedbooleantransform(MessageExchange
exchange,NormalizedMessagein,NormalizedMessage
out)throwsMessagingException
{
StringcorrelationId=
(String)exchange.getProperty(
Constants.CORRELATION_ID_KEY);
System.out.println("AddressValidationService.transform.
correlationId:"+correlationId);
Sourcecontent=in.getContent();
StringcontentString=null;
AddressTOaddressTO=null;
if(contentinstanceofStreamSource)
{
contentString=XMLUtil.formatStreamSource(
(StreamSource)content);
(StreamSource)content);
addressTO=(AddressTO)XStreamUtil.
xmlToObject(contentString);
}
else
{
log.debug("AddressValidationService-
content.getClass():"+content.getClass()+";
content:"+content);
}
out.setProperty(Constants.ADDRESS_VALIDATED_KEY,
Boolean.TRUE);
serviceaggregation,businessintegration
samplemessageexchange,sequence3returntrue;
}
}
WhentheAddressservicereturns,theonMessageExchangemethodinthebrokerwillbeinvoked(Sequence1).NowasthebrokercomponentisintheconsumerroleandtheLocalPartis"address",thecontrolflowstotheprocessAddressValidationResponsewhichisgiveninSequence4.
InprocessAddressValidationResponsewecheckwhethertheaddressisvalidated.Ifnot,wesettheXMLmessage"<AddressNotValidated/>"atthenormalizedMessagetotheRootExchangesothatthemessageexchangeflowwillbecompletedandcontrolflowsbacktothedeliveryChannelfirstandthentotheclient.Ifaddressisvalidated,wecreateanewInOutexchangewithcreditGateWayastheLocalPartandsendittothedeliveryChannel.
Inboththescenariosabove,notethatwesetthe(AddressValidation)messageExchangestatusto"done".Thecodelistinginthefollowingshowsprocessingtheaddressvalidationresponse:
publicclassSyncVoipBrokerextends
ComponentSupportimplements
MessageExchangeListener
MessageExchangeListener
{
privatevoid
processAddressValidationResponse(MessageExchange
exchange)throwsMessagingException
{
StringcorrelationId=(String)
getProperty(exchange,
Constants.CORRELATION_ID_KEY);
System.out.println("SyncVoipBroker.
processAddressValidationResponse.correlationId:
"+correlationId);
booleanisAaddressValidated=((Boolean)
getOutProperty(exchange,
Constants.ADDRESS_VALIDATED_KEY)).booleanValue();
MessageExchangerootExchange=null;
if(isAaddressValidated)
{
InOutinout=createInOutExchange(newQName(
creditGatewayNamespaceURI,
creditGatewayLocalPart),null,null);
inout.setProperty(Constants.CORRELATION_ID_KEY,
correlationId);
NormalizedMessagemsg=inout.createMessage();
inout.setInMessage(msg);
send(inout);
}
else
{
rootExchange=(MessageExchange)aggregations.
get(correlationId);
serviceaggregation,businessintegration
samplemessageexchange,sequence
4NormalizedMessageresponse=
rootExchange.createMessage();
response.setContent(newStringSource("
<AddressNotValidated/>"));
rootExchange.setMessage(response,"out");
send(rootExchange);
aggregations.remove(correlationId);
}
done(exchange);
done(exchange);
}
}
Assumingthe"AddressValidated"scenarioasthenormalflow,thenewlycreatedMessageExchangewillnowagaininvoketheonMessageExchangemethodoftheCreditGateway(whichinturncallsthetransformmethodofcreditGateway—Sequence5).WhentheCreditGatewayservicereturns,theonMessageExchangemethodinthebrokerwillbeinvokedagain,thistimealsointheconsumerrole—consumertotheCreditGatewayservice.TheCreditGatewayserviceissimple.TheSequence5isshowninthefollowingfigure:
IntheCreditGatewayservicewecreatearecipientlistandsetitasapropertyinthe"out"messageoftheMessageExchange.Thisisshowninthefollowingcode:
publicclassCreditGatewayextends
TransformComponentSupport
{
privateMapendPoints;
publicvoidsetEndPoints(MapendPoints)
{
this.endPoints=endPoints;
}
protectedbooleantransform(MessageExchange
exchange,NormalizedMessagein,NormalizedMessage
out)throwsMessagingException
{
StringcorrelationId=
(String)exchange.getProperty(
Constants.CORRELATION_ID_KEY);
System.out.println("CreditGateway.transform.correlationId
:"+correlationId);
out.setProperty(Constants.RECIPIENTS_KEY,
getRecipients());
returntrue;
}
privateQName[]getRecipients()
{
QName[]recipients=newQName[endPoints.size()];
StringtheNamespaceURI=null;
StringtheLocalPart=null;
inttimes=0;
for(Iteratoriterator=
endPoints.keySet().iterator();
iterator.hasNext();)
{
theLocalPart=(String)iterator.next();
theNamespaceURI=(String)
endPoints.get(theLocalPart);
recipients[times++]=newQName(theNamespaceURI,
theLocalPart);
}
returnrecipients;
}
}
Herewegenerateastaticrecipientlist.Therecipientlistisconfiguredintheservicemix.xmlfilefortheCreditGatewaycomponentasshownhere:
<sm:activationSpeccomponentName="creditGateWay"
endpoint="creditGateWay"
service="binil:creditGateWay">
<sm:component>
<bean
class="com.binildas.esb.servicemix.serviceassembly.
voipservice.CreditGateway">
<propertyname="name">
<value>Credit</value>
</property>
<propertyname="endPoints">
<map>
<entrykey="creditAgency">
<value>http://www.binildas.com/voipservice</value>
</entry>
<entrykey="bankAgency">
<value>http://www.binildas.com/voipservice</value>
</entry>
</map>
</property>
</bean>
</sm:component>
</sm:activationSpec>
WhentheCreditGatewayservicereturns,theonMessageExchangemethodinthebrokerwillbeinvoked(Sequence1).NowasthebrokercomponentisagainintheconsumerroleandtheLocalPartis"creditGateWay",thecontrolflowstotheprocessCreditGatewayResponsewhichisgivenin
Sequence6.Thisisshowninthefollowingfigure:
Ournextaimistoroutethemessagetoallthetargetsdefinedintherecipientlist.WecreateasmanynewInOutexchangesasthereareentriesintherecipientlistandsendthemtothedeliverychannel.Thefollowingcodesnippetdetailsoutthesesequenceofevents:
publicclassSyncVoipBrokerextends
ComponentSupportimplements
MessageExchangeListener
{
privatevoid
processCreditGatewayResponse(MessageExchange
exchange)throwsMessagingException
{
StringcorrelationId=(String)
getProperty(exchange,
Constants.CORRELATION_ID_KEY);
System.out.println("SyncVoipBroker.
System.out.println("SyncVoipBroker.
processCreditGatewayResponse.correlationId:"+
correlationId);
QName[]recipients=(QName[])
getOutProperty(exchange,
Constants.RECIPIENTS_KEY);
CreditCardTOcreditCardTO=((ServiceParamTO)
payLoad).getCreditCard();
StringxmlCreditCard=
XStreamUtil.objectToXml(creditCardTO);
SourcecreditCardSource=null;
InOutinout=null;
NormalizedMessagemsg=null;
for(intqNames=0;qNames<recipients.length;
qNames++)
{
inout=createInOutExchange(recipients[qNames],
null,null);
inout.setProperty(Constants.CORRELATION_ID_KEY,
correlationId);
msg=inout.createMessage();
creditCardSource=newStreamSource(new
ByteArrayInputStream(xmlCreditCard.getBytes()));
msg.setContent(creditCardSource);
inout.setInMessage(msg);
stack++;
send(inout);
}
done(exchange);
}
}
Herewesendthecreditcarddetailstotherecipients(BankAgency&CreditAgency).
ThenewlycreatedmessageexchangeswillnowinvoketheonMessageExchangemethodoftheBankAgency&CreditGateway(whichinturncallsthetransformmethodof
BankAgency&CreditAgencyrespectively)whichisagainsimpleandisshowninSequence7andSequence8.Thecodeisnotreproducedhere,sincetheyareverytrivial.TheSequence7isshowninthefollowingfigure:
TheSequence8isshowninthefollowingfigure:
WhentheBankAgencyortheCreditAgencyservicesreturns,theonMessageExchangemethodinthebrokerwillbeinvokedagainintheconsumerrole—consumertotheBank
AgencyandCreditAgency.Inboththescenarios,thecontrolwillbethetransformmethod.
TheSequence9isshowninthefollowingfigure:
LetusnowlookintothecodeofprocessServiceRequestindetail:
publicclassSyncVoipBrokerextends
ComponentSupportimplements
MessageExchangeListener
{
privatevoid
processServiceRequest(MessageExchangeexchange)
throwsMessagingException
{
StringcorrelationId=(String)
getProperty(exchange,
Constants.CORRELATION_ID_KEY);
Constants.CORRELATION_ID_KEY);
System.out.println("SyncVoipBroker.processServiceRequest.
correlationId:"+correlationId);
Booleancreditauthorized=(Boolean)
getOutProperty(exchange,
Constants.CREDIT_AUTHORIZED_KEY);
Booleangoodhistory=(Boolean)
getOutProperty(exchange,
Constants.GOOD_HISTORY_KEY);
MessageExchangerootExchange=(MessageExchange)
aggregations.
get(correlationId);
done(exchange);
stack--;
if(((creditauthorized!=null)&&!
(creditauthorized.equals(Boolean.TRUE)))||
((goodhistory!=null)&&!
(goodhistory.equals(Boolean.TRUE)))){
creditVetoed=true;
System.out.println("SyncVoipBroker.processServiceRequest
-creditVetoed:"+creditVetoed);
}
if(0==stack)
{
NormalizedMessageresponse=
rootExchange.createMessage();
if(creditVetoed)
{
response.setContent(newStringSource("
<ServiceNotProvisioned/>"));
}
else
{
response.setContent(newStringSource("
<ServiceProvisioned/>"));
}
rootExchange.setMessage(response,"out");
send(rootExchange);
aggregations.remove(correlationId);
}
}
}
}
Here,basedontheoutcomeofthepreviousserviceresponseswecandecidewhethertheservicecanbeprovisionedornotandaccordinglywecancreateanXMLmessage.Nowcomesthedifference—wecreateanormalizedmessageoutoftheRootExchange(wearenotgoingtocreateanewmessageexchange,sincewearealmostdonewiththeprocess),settheXMLmessageasitscontentandcallsendontherootExchange.
TheRootExchangewillagainberoutedthroughthedeliverychannelbacktotheonMessageExchangeoftheBroker,butthistimethemessageexchangestatusisalreadysetas"DONE".SoasshowninSequence1,thebrokernowreturnsbacktothedeliverychannelandthedeliverychannelinturnsendsbackanyresponsetotheclient.
Thiscompletestheentireprocess.
DeployingandRunningtheSampleAsafirststep,ifyouhaven'tdoneitbefore,editexamples.PROPERTIES(providedalongwiththecodedownloadforthischapter)andchangethepathstheretomatchyourdevelopmentenvironment.Nowtobuildtheentirecodebaseanddeploythesampleinasinglego,changedirectorytoch16\voipservicewhichcontainsatop-levelbuild.xmlfile.Executeantthere.
cdch16\voipservice
ant
Now,bringuptheServiceMixcontainerbyexecutingthebroker.xmlfilecontainedinthesamefolder.
cdch16\voipservice
%SERVICEMIX_HOME%/bin/servicemixbroker.xml
TheClient.htmlfileprovidedagaininthesamefoldercanbeusedtosendmessagestotestthedeployedservice.
ThemessageexchangeswedescribedintheprevioussectioncanbeunderstoodbetterbylookingattheServiceMixconsoleloggingshowninthefollowingscreenshot:
SummaryMOMhasbeenservingasagreatenablerforcreatinglooselycoupledapplicationsformanyyears.NowMOMprovidesustheEAIpatterntointegratenotonlyapplicationsbutalsoservicesandcomponentsinaseamlessmanner.
Distributedcomponentsarethenormintoday'senterprise
computing,aggregating,andorchestratingthemessageflowsacrosssuchmultiplecomponentsprovideuswithanewflexibilityindefiningbusinessprocess—byseparatingoutindividualservicesintomultiplecomponentsandthusreducingtheoverallcomplexityoftheprocess.
Weusethe"divideandrule"principletomanagethecomplexitybysplittingoutthefunctionalityintomultiplecomponentsandservices.However,thenthesedistributedcomponentshavetointegratetogethertoprovideaggregateorcompositeserviceswhichwecandoattheESB-level.Youhaveseensuchasampleinthischapter.
InthenextchapterwewilllookattheJBIbusinaslightlydifferentperspective—inanon-functionaloraQOSperspective.
Chapter17.Transactions,Security,Clustering,andJMXNobookonprogrammingwithanyframeworkwillbecompletewithoutamentionofthevariousnonfunctionalandQOSfeaturessupportedbytheframework.InthischapterwewillvisitafewselectedQOSfeatureswhichhaveanimpactontheprogramminganddeploymentaspectsusingtheServiceMixESB,whicharelistedasfollows:
Transactions
Security
Clustering
JMX
Infact,ifwehavetoaddresstheabovefeaturesexhaustivelythenwemayneedmanypages(orasinglebookbyitself).However,asthisbookisintendedtocovermanyotheraspects,wewilllimitourdiscussiontoasinglechapter.AtthesametimewewillseethatthereaderwillnotonlyhaveanoverviewoftheabovefeatureswithinServiceMix,butalsoisequippedwiththetools,codesamples,anddesignaspectssoastoenablehimforfurtherreadinganddevelopment.
Inthischapterwewilllookintothefollowing:
CrosscuttingconcernsinServiceMix
Samplesdemonstratingtransactions,security,clustering,andJMX
CrossCuttingConcerns—SupportInsideServiceMixThischapterisslightlydifferentfromothersbecausealmostalltheotherchaptersweredealingwithaparticularwayofbindingservicestoServiceMix.Inthischapterwearegoingtoaddressprogrammingand/ordeploymentconcernswhichcanbeappliedacrossanyorallofthebindingmechanismscoveredintheotherchapters.
Justasitispossibleinnormalprogrammingsuchaswebcomponentdevelopmentorserver-sidebusinesscomponentdevelopment,wecanalsoattachvariousQOSfeaturestothecomponentdeploymentmodelinServiceMix.ThepeculiarthingwiththeseQOSfeaturesisthattheyarenothardwiredthroughcodealongwiththeBCsorSEs,butappliedoverthecomponentsinadeclarativemanner.TheadvantageisthatthecharacteristicsoftheseQOSfeaturescanbeeasilychangedbyalteringtheparticularconfiguration.
LetusnowlookintotheselectedQOSfeaturesandtheirsupportwithinServiceMix.
TransactionsTransactionsguaranteeatomicityoftheoperations(messageflows)betweenthecomponents.Weknowthatvarious
componentscanbepluggedintotheJBIbuswhichcantakepartinthemessageexchange.Transactionscanbeassociatedwiththesemessageexchangeflows.Thescopeandsynchronicityofthesetransactionsmainlydependsuponwhich"send"primitiveweusetoexchangemessagesbetweencomponents.
TheServiceMixJBIprovidesanoptiontosettransactionsatthecontainer-level.ThefollowinglistingshowshowtoenlistJBIexchangesintransactions.
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0">
<sm:containerid="jbi"embedded="true"
depends-on="jndi,broker"
autoEnlistInTransaction="true"
transactionManager="#transactionManager">
</sm:container>
<jencks:transactionManager
id="transactionManager">
<beans>
WecansettheautoEnlistInTransactionattributefortheServiceMixJBIcontainertotruesothateverytimeaJBIexchangeissent,itwillbeenlistedinthecurrenttransaction.
WecannowusesendorsendSynctosendthemessageexchangesanddependinguponwhichoneisused,thesemanticsoftransactionpropagationalsoisdifferent.
IfsendSyncisusedtosendanexchange,theimplied
semanticisthatthetransactionflowswiththeexchangeandthattheserviceproviderhastoanswersynchronouslyandalsoenlistanyrequiredresourcesinsidethetransaction.InChapter3wediscussedaboutthevariousflow(NMRFlows)optionsavailablewithinServiceMixofwhichtheJCAflowneedsspecialattention.Theservicemixjmscomponent,ifusedinaJCAflow,canstarttransactionswhereastransactionswithinasynchronousflowarenotcreatedbydefault.
ThefollowingfigureshowsthepropagationoftransactioncontextwhensendSyncisused:
Ifweusesend,thesendingofthemessagewillbeenlistedinthecurrenttransaction,butthemessageexchangeprocessing
willbedeferredandthenhandledinitsownthreaddisjointfromtheprevioustransaction.WehavetousetheJCAflowtousethetransactionswiththeasynchronousmessageexchanges.Asampleflowisshowninthefollowingfigure:
Programmingthetwotypesofsynchronicityoftransactioninthemessageexchangeareshowninthefollowinglist:
Programmingsynchronoustransactionalexchange:SynonymoustotheJDBCAPI,weneedtofirstgetahandletotheunderlyingTransactionManagerandthenmarkthetransactiontobegin.ThenwesendthemessageexchangeusingsendSyncfollowedbyacommitorarollback.Thesequencesofstepsareshownhere:
TransactionManagertxManager=
(TransactionManager)
(TransactionManager)
jbiContext.getTransactionManager();
tm.begin();
InOnlymessageExchange=createInOnly();
jbiContext.getDeliveryChannel().sendSync(messageExchange);
tm.commit();
Programmingasynchronoustransactionalexchange:Creatingasynchronoustransactionalexchangeissimilartothesynchronousmethod,butweusesendinsteadofsendSync.
TransactionManagertxManager=
(TransactionManager)
jbiContext.getTransactionManager();
tm.begin();
InOnlymessageExchange=createInOnly();
jbiContext.getDeliveryChannel().send(messageExchange);
tm.commit();
Thelatersectionsinthischapterwillhaveworkingsampleswhichwillmakeclearthepointsexplainedhere.
SecurityServiceMix'sHTTPcomponentnamelyservicemix-httpprovidesfacilitytoconfiguresecurity.Letuslookatafewofthemlistedhere:
HTTPbasicauthentication:HTTP1.1specificationsdefinesbasicauthentication.Asperthat,whenaclienttriestoaccessaresourcemarkedasprotectedintheserver,theserverpromptsforausernameandpasswordcombination.Thisisfollowedbythebrowserpromptingwithausernameandpasswordentryformwheretheusercanentertherelevantinformationandsubmit.Iftheusernameandpasswordenteredbytheuseris
authenticatedbytheserver,accesswillbegrantedtotherequestedresource.Otherwise,dependingupontheserver'spolicy,thepromptwillberepeatedforafewtimes(usuallythree).ThemaindrawbackwithHTTPbasicauthenticationisthatthepasswordsaresentacrossthenetworkbase64encoded,whichisakindofplaintextformat.Asthepasswordsarenotencrypted,theyarevulnerabletohacks.Henceasanadditionalprecaution,wecaneitherdoencryptionorusesomeotherstrongermechanism.
Fortheservicemix-httpcomponent,wecanconfigurebasicauthenticationbyconfiguringtheendpointasshowninthefollowingcode:
<http:endpointservice="test:httpConsumer"
endpoint="httpConsumer"
targetService="test:echo"role="consumer"
locationURI="http://localhost:8198/Service/"
authMethod="basic"
defaultMep="http://www.w3.org/2004/08/wsdl/in-
out">
</http:endpoint>
Inthiscase,beforetheservicemix-httpcomponentroutestherequesttothetargetService,abasicauthenticationchallengeisinitiatedbytheserverandtherequestwillberoutedtothetargetServiceifandonlyiftheusernameandthepasswordenteredbytheusermatcheswithwhatisconfiguredinthecontainer.
SSL:ServiceMixcanbeconfiguredtousesecuretransportusingSSL.
TheHTTPconsumerrolefortheservicemix-httpcomponentcanbeconfiguredtouseSSLasfollows:
<http:endpoint
service="test:YourConsumerService"
endpoint="yourConsumer"role="consumer"
locationURI="https://localhost:8193/Service/"
defaultMep="http://www.w3.org/2004/08/wsdl/in-out">
<http:ssl>
<http:sslParameters
keyStore="classpath:com/binildas/esb/
servicemix/security/server.keystore"
keyStorePassword="keystorepassword">
<http:ssl>
</http:endpoint>
Intheconsumerrole,test:YourConsumerServicewillbesetasthedestinationfortheaboveconsumerafterthemessageisreceivedthroughtheSSLtransport.
Similarly,theHTTPproviderrolefortheservicemix-httpcomponentcanbeconfiguredtouseSSLasfollows:
<http:endpoint
service="test:YourProviderService"
endpoint="yourProvider"role="provider"
locationURI="https://localhost:8193/Service/"
defaultMep="http://www.w3.org/2004/08/wsdl/in-out">
<http:ssl>
<http:sslParameters
keyStore="classpath:com/binildas/esb/
servicemix/security/server.keystore"
keyStorePassword="keystorepassword"
trustStore="classpath:com/binildas/esb/
servicemix/security/client.keystore"
trustStorePassword="truststorepassword">
<http:ssl>
</http:endpoint>
WewillhaveaworkingsampledemonstratingHTTPbasicsecuritylaterinthischapter.
ClusteringArchitectinganddesigninganapplicationbylookingattheNonFunctionalRequirements(NFR)alongwiththeusualfunctionalrequirementsisimportanttoensurefailsafeoperationundernormalaswellasabnormalusageconditions.
Therecanbespecifichoursinadayorspecificmonthsduringayearwhenyourapplicationwillreceivemorehitsthannormal.Theapplicationsneedtobedesignedtakingthisintoaccount.
Thescalabilityandavailabilityofanyapplicationdependsonthemultiplelayersintheapplicationdeploymentstack.Thefollowinglistgivesafewofthemainaspects:
Applicationalgorithmsanddesignpatterns.
Applicationframeworksforfunctionalitiessuchascaching,sessionreplication,andpersistence.
Operatingsystemsupportprovidingheaplimit,greenthreads,andnativethreads.
Hardwareinfrastructure,providing32or64bitwordcapability.
Theabovelistisneverexhaustive,butjustthemainandevidentlayers.
Theavailabilityofanyapplicationdependsontheabilityofthedeploymentenvironmenttorecoverfromafailurewithaminimumamountofdowntimewithoutanydatacorruption.Softwareandhardwarearepronetofailure,butthatisnoreasontoshowback"Applicationnotavailable"messagestotheenduserthroughthebrowser.Suchascenariowillcreateunsatisfiedcustomerswhomightmigratetoacompetitor'sservice.Weallagreethatretaininganexistingcustomerisas(ormore)importantthangaininganewcustomer.
Onewaytoaddresssoftwareandhardwarefailureistoleveragetheindustry-leadingclusteringsolutionstodeliver
best-in-classhighavailability,manageability,andperformanceforapplicationsinenterpriseandapplicationservicegridenvironments.Ifwedon'twanttogoforsuchthird-partyclusteringservices,wecanalsoseewhetherourownchosenapplicationinfrastructure(suchasServiceMix)willprovideitsownclusteringfeatures.So,letusunderstandtheServiceMixclusterinmoredetail.
AServiceMixclusterisalogicalgroupingofmultipleServiceMixinstancesrunningsimultaneouslyandworkingtogetherthusprovidingincreasedscalabilityandreliability.Fromaclientoraconsumerperspective,theclusteristransparent.Thismeans,aServiceMixclusterappearstoclientstobeasingleServiceMixcontainerinstance.TheServiceMixinstancesthatparticipateinaclustercanrunonthesamemachine,orbelocatedondifferentmachines.YoucanalsoincreaseaServiceMixcluster'scapacitybyaddingadditionalServiceMixinstancestotheclusteronanexistingmachine,oryoucanalsoaddnewmachinestotheclustertohostnewServiceMixserverinstances.
IndividualcomponentsorapplicationcomponentsneedtobeinstalledtotheServiceMixserverinstancestakingpartinthecluster.ItisrecommendedtofollowauniforminstallationschemawherewewilldeploycomponentshomogenouslyintoalltheServiceMixserverinstancesinthecluster.However,thisisnotmandatoryasisshownintheclusteringsampleweprovidelaterinthechapter.TheexacttopologyanddeploymentschemaforaServiceMixclusterhastobedecidedbasedonwhatlevelofQOSfeatureswearetargetingfromeachofthedeployedcomponents.
TherearemultiplebenefitswhichwecanleveragefromaServiceMixclusteringtopology,afewofthemarelistedasfollows:
Scalability:Asoftwaresystemissaidtobescalableifitsperformancedoesnotdegradesignificantlyastheloadonthesystemincreases.ThescalabilityofaServiceMixclustercanbeincreaseddynamicallytomeetthedemand.YoucanaddtheServiceMixinstancestoaclusterwithoutinterruptionofthedeployedservice—theapplicationsandservicesalreadydeployedcontinuetorunwithoutimpacttotheexistingconsumers.
Highavailability:Availabilityisdefinedasthefractionoftimethesoftwaresystemisupandavailabletoitsconsumers.
NOTENOTE
Forexample,asystemwith99.99%availabilityoveraperiodof1yearwouldbeunavailablefor:
(1-0.9999)X1YearX365DaysX24HoursperDayX60MinutesperHour=52.56Minutes.
Formanysystemssuchastheweb-basede-commercesystemsa99.99%availabilitywouldbesufficientbutformanyothersystemslikethoseusedforlifesavingordefencepurposesahigher-levelofavailabilitywouldberequired.
InaServiceMixcluster,SEsandBCscanstillcontinuetoruninadifferentserverinstancewhenoneoftheserverinstancesfails.Asyoucandeploytheapplicationcomponentstomultipleserverinstancesinthecluster,ifaserverinstanceonwhichacomponentisrunningfails,anotherserverinstanceonwhichthatcomponentisdeployedcancontinuetheprocessingthusincreasingtheoverallsystemavailability.
Loadbalancing:LoadbalancingistheevendistributionofjobsandprocessesacrossthecomputingandnetworkingresourcesinyourServiceMixcluster.Forloadbalancingtooccur,theremustbemultiplecopiesofaServiceMixcomponentthatcanserveaparticularconsumer.InformationaboutthelocationandoperationalstatusofalltheServiceMixcomponentsmustbeavailablecentrallyandacross.
TosetupaServiceMixcluster,aJMSflowisused.TheJMSflowcollaboratesthecommunicationbetweenmorethanoneServiceMixJBIcontainerinstance.AmessagequeueisusedforeachJBIendpoint,sothatmultipleinstancesofthesamenamedcomponentdeployedindifferentinstancesoftheServiceMixintheclusterhaverequestsloadbalancedacrossthem.
InaServiceMixcluster,deploymenthappensinthesamewayaswedoinanormalServiceMixJBIcontainer(bothforPOJOandarchiveComponentdeployment)butallServiceMixcontainerinstancesintheclusterarenotifiedofadeployment.TheunderlyingJMSflowwillhandleautomaticrouting,loadbalancing,andfailoverofMessageExchange(s)betweenthedifferentServiceMixcontainersinstancesinthecluster.
IntheclustermodeallServiceMixinstancesparticipatingintheclustermusthaveauniquenameinthewholecluster.Letuslookintoasampleconfigurationtounderstandthiswell.Inourhypotheticalsamplecluster,assumethatwewillhavethreeServiceMixcontainersinstances.AsoneoftheseServiceMixinstancesalsomanagesaJMSconnectionbroker,wewillarbitrarilynamethatinstancewiththename"admin".
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0">
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<beanid="jndi"
class="org.apache.xbean.spring.jndi.
SpringInitialContextFactory"
factory-method="makeInitialContext"
singleton="true">
<sm:containerid="jbi"name="admin"
flowName="jms?jmsURL=tcp:/localhost:61616"
useMBeanServer="true"createMBeanServer="true"
rmiPort="1111">
<sm:activationSpecs>
<!--othercode-->
</sm:activationSpecs>
</sm:container>
<beanid="broker"
class="org.apache.activemq.xbean.BrokerFactoryBean">
<propertyname="config"
value="classpath:activemq.xml">
<bean>
<beanid="jmsFactory"
class="org.apache.activemq.pool.PooledConnectionFactory">
<propertyname="connectionFactory">
<refbean="connectionFactory">
<property>
</bean>
<beanid="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<propertyname="brokerURL"
value="tcp://localhost:61616">
<bean>
</beans>
Theimportantthingtonotehereisthat,wefirstsettheflowNametobeofJMStypeandthensetthejmsURLtopointtothelocationwheretheJMSbrokerislistening.Now,wecanaddanynumberofinstancesfortheServiceMixtothecluster,simplybypointingthemtothesameJMSbroker.ForoursamplepurposewewillhavetwoinstancesforServiceMix
named"managed1"and"managed2".
Theflowsettingsformanaged1areshowninthefollowingcode:
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
>
<beanid="jndi"
class="org.apache.xbean.spring.jndi.
SpringInitialContextFactory"
factory-method="makeInitialContext"
singleton="true">
<sm:containerid="jbi"name="managed1"
flowName="jms?jmsURL=tcp:/localhost:61616"
useMBeanServer="true"createMBeanServer="true">
<sm:activationSpecs>
<!--othercode-->
</sm:activationSpecs>
</sm:container>
</beans>
Wewillhaveasimilarconfigurationformanaged2.Thisislistedinthefollowingcode:
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
>
<beanid="jndi"
class="org.apache.xbean.spring.jndi.
SpringInitialContextFactory"
factory-method="makeInitialContext"
singleton="true">
<sm:containerid="jbi"name="managed2"
flowName="jms?jmsURL=tcp:/localhost:61616"
useMBeanServer="true"createMBeanServer="true">
<sm:activationSpecs>
<!--othercode-->
</sm:activationSpecs>
</sm:container>
</beans>
Wewilllookintoaclusteringsamplewithcodelaterinthischapter.
JMXJMX(JavaManagementExtensions)technologyprovidestherequiredAPIsandtoolsforbuildingdistributed,web-based,modular,anddynamicsolutionsformanagingandmonitoringdevices,applications,andservice-drivennetworks.StartingwiththeJ2SEplatform5.0,JMXtechnologyisincludedintheJavaSEplatform.
TheServiceMixJBIContainerwillexposeinternalservicesandcomponentsthroughtheJMX.TheJBIContainercanbepassedasaJMXBeanServer.Alternatively,itcanbeconfiguredtocreateoneifitdoesn'texist.
ThefollowingcodewillcreatearemoteJMXConnectortotheJBIContainer:
StringjndiPath="jmxrmi";
JMXServiceURLurl=newJMXServiceURL
("service:jmx:rmi:///jndi/rmi://127.0.0.1:1099/"
+jndiPath);
JMXConnectorconnector=
JMXConnectorconnector=
JMXConnectorFactory.connect(url);
ConfiguringJMXinServiceMixisdoneinthejmx.xmlfileagainfoundintheconfdirectory.Thefollowingcodeshowshowtodothis:
<sm:jmxConnectorobjectName="connector:name=rmi"
serviceUrl="${jmx.url}"
threaded="true"
daemon="true"
depends-on="rmiRegistry,jndi"
environment="#jmxConnectorEnvironment"/>
Thejmx.urlisservice:jmx:rmi:///jndi/rmi://localhost:10
99/jmxrmi.
ThesearethedefaultsettingsforServiceMixversion3.x.Forversion2.x,jmx.urlchangestoservice:jmx:rmi:///jndi/rmi://localhost:10
99/defaultJBIJMX.
OnceServiceMixisupandrunning,thenyoucanuseanyJMXcompatibleconsoletoolstoconnecttotheServiceMixcontainer.Wewilldemonstratethislaterinthischapter.
SampleDemonstratingTransaction
Inthissectionwewilldemonstrateconfiguringtransactionsforamessageexchangeinanasynchronouspattern.
SampleUseCaseInthesamplescenariotodemonstratetransactions,wewillconfigureDefaultServiceMixClientwithintheJBIcontainerastheclientorconsumerfortheJBIbus.WewillfirststartatransactionandthenaskDefaultServiceMixClienttosendanInOnlymessageexchangetotheJBIbus.Wewilluse"send"heresothattheactofsendingthemessagewillbeenlistedinthecurrenttransaction,buttheprocessingofthemessageexchangewillbedeferredandhandledinaseparatethread.
WewillhaveaservicemixjmscomponentconfiguredintheproviderroletowhichtheDefaultServiceMixClientcantargetmessageexchange.WethenhaveaservicemixjmsintheconsumerroletowhichtheJMSproviderpipelinesmessages.FortheJMSconsumer,wehaveconfiguredaReceivercomponentusingthetargetServiceattribute.HenceanymessagesinthechainwillbeultimatelyroutedtotheReceivercomponent.
Thecomponentsetupisshowninthefollowingfigure:
Inthesample,weuse"send"forsendingthemessage.Hencesendingwillbeenlistedinthecurrenttransactionwhichincludesreceptionofthemessagebythebus.Anyfurtherprocessing,includingforwardingthemessagetothenextcomponentwillbedeferredandhandledinseparatethreads.
ConfigureTransactioninServiceMixAllthecomponentsspecifiedintheselectedusecaseareconfiguredintheservicemixjms.xmlfileasshownhere:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0"
xmlns:amq="http://activemq.org/config/1.0"
xmlns:amqra="http://activemq.org/ra/1.0"
xmlns:jencks="http://jencks.org/2.0"
xmlns:test="http://binildas.com/esb/servicemix/tx/
jms/inonlyasync">
<sm:containerid="jbi"embedded="true"
depends-on="jndi,broker"
autoEnlistInTransaction="true"
transactionManager="#transactionManager">
<sm:flows>
<sm:sedaFlow>
<sm:jcaFlow
connectionManager="#connectionManager"
jmsURL="tcp:/localhost:61616?
jms.asyncDispatch=true&
jms.useAsyncSend=true">
<sm:flows>
<sm:activationSpecs>
<sm:activationSpec>
<sm:component>
<jms:component>
<jms:endpoints>
<jms:endpointservice="test:MyConsumerService"
endpoint="consumerEP"
targetService="test:MyReceiverService"
role="consumer"
defaultMep="http://www.w3.org/2004/
08/wsdl/in-only"processorName="jca"
connectionFactory="#connectionFactory"
resourceAdapter="#resourceAdapter"
bootstrapContext="#bootstrapContext"
synchronous="false">
<jms:activationSpec>
<amqra:activationSpecdestination="queue/A"
destinationType="javax.jms.Queue">
<jms:activationSpec>
</jms:endpoint>
<jms:endpointservice="test:MyProviderService"
endpoint="providerEP"role="provider"
processorName="jca"connectionFactory="
#connectionFactory"destinationStyle="queue"
jmsProviderDestinationName="queue/A">
<jms:endpoints>
</jms:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpecid="receiver"
service="test:MyReceiverService"
endpoint="receiverEP">
<sm:component>
<beanclass="org.apache.servicemix.tck.
ReceiverComponent">
<sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
<beanid="client"
class="org.apache.servicemix.client.
DefaultServiceMixClient">
<constructor-argref="jbi">
<bean>
<beanid="jndi"
class="org.apache.xbean.spring.jndi.
SpringInitialContextFactory"
factory-method="makeInitialContext"
singleton="true">
<propertyname="entries">
<map>
<entrykey="jms/ConnectionFactory"
value-ref="connectionFactory">
<map>
</property>
</bean>
<amqra:managedConnectionFactoryid="activemqMCF"
resourceAdapter="#resourceAdapter">
<amqra:resourceAdapterid="resourceAdapter"
serverUrl="tcp:/localhost:61616?
jms.asyncDispatch=true&
jms.useAsyncSend=true">
<jencks:connectionFactoryid="connectionFactory"
managedConnectionFactory="#activemqMCF"
connectionManager="#connectionManager">
<amq:brokerid="broker"persistent="false">
<amq:transportConnectors>
<amq:transportConnector
uri="tcp://localhost:61616">
<amq:transportConnectors>
</amq:broker>
<jencks:transactionManager
id="transactionManager">
<jencks:workManagerid="workManager"
transactionManager="#transactionManager">
<jencks:bootstrapContextid="bootstrapContext"
workManager="#workManager"
transactionManager="#transactionManager">
<jencks:connectionTrackerid="connectionTracker"
geronimoTransactionManager="#transactionManager"
>
<jencks:poolingSupportid="poolingSupport"
allConnectionsEqual="false"/>
<jencks:connectionManagerid="connectionManager"
containerManagedSecurity="false"transaction="xa"
transactionManager="#transactionManager"
poolingSupport="#poolingSupport"
connectionTracker="#connectionTracker">
<beans>
Inordertoleveragetransactionswithasynchronousmessageexchanges,theJCAflowmustbeused.ThisiswhatwedobyincludingjcaFlowinsidetheflowselement.WhileweconfiguretheJBIcontainer,ifwesettheautoEnlistInTransactionflagtotrue,eachtimeaJBIexchangeissent,itwillbeenlistedinthecurrenttransaction.
DeployandRuntheSampleBeforerunninganysamplesinthischapter,ifyouhaven'tdoneitbeforeeditexamples.PROPERTIES(providedalongwiththecodedownloadforthischapter)andchangethepathstheretomatchyourdevelopmentenvironment.
Nowtobuildtheentiresample,itiseasiertochangedirectorytothetop-levelfolderandexecutethebuild.xmlfileprovidedthere:
cdch17\01_Transactions\InOnlyAsync
ant
Thiswillbuildtheentirecodebaseforthetransactiondemonstration.NowweneedtoopenanothercommandpromptandstartServiceMixintheembeddedmode,asfollows:
cdch17\01_Transactions\InOnlyAsync
antrun
IncaseyouwanttorunthetestasaJUnittestcase,executethefollowingcode:
anttest
Attheendoftherun,wewillattempttoclosetheJBIcontainerbydestroyingthecontext.AswearestartingtheServiceMixinembeddedmodeitwillgenerateexceptionsin
theconsole.Theseerrorscanbeignored.Insteadyoucanconcentrateontheapplicationloggingwhichisreproducedhere:
[junit]JmsInOnlyAsyncTest.testJmsInOnlySync-
Start...
[junit]JmsInOnlyAsyncTest.testJmsInOnlySync-
TransactionCommitted.
[junit]INFO-MessageList-Waitingformessage
toarrive
[junit]INFO-MessageList-Endofwaitfor1001
millis
[junit]JmsInOnlyAsyncTest.testJmsInOnlySync-
End.
[junit]JmsInOnlyAsyncTest.tearDown...
[junit]ClosingdowntheSpring
ApplicationContext
WecanseethattheMessageListwaitsformessageswhichitreceivesattheendof1001milliseconds.ThefollowingscreenshotshowstheESBconsole:
SampledemonstratingSecurityThesecurityinServiceMixcanbeconfiguredatmultiple
levelsandatmultiplelayers.Inthissectionwewilldemonstrateasimplesecurityconfigurationfortheservicemix-httpcomponent.WewillconfigureHTTPbasicauthenticationandasperthat,whenaclienttriestoaccessaresourcemarkedasprotectedintheserver,theserverpromptsforausernameandpasswordcombination.Thisisfollowedbythebrowserpromptingwithausernameandpasswordentryformwheretheusercanentertherelevantinformationandsubmit.
SampleUseCaseThesetupofcomponentsforthesampleusecaseisshowninthefollowingfigure:
Thesecuritysampleusecasewillhaveservicemix-httpconfiguredintheconsumerrole,listeningforHTTPtransportforaparticularport.WethenconfigureanEchoservicecomponentasthetargetServicefortheaboveHTTPconsumer.Whendoingso,wealsotellthattheHTTPbasicauthenticationhastobeapplied.AnexternalHTTPclientprovidedcanbeusedtotargetmessagestotheHTTPconsumer.Whentheexternalclientsendsrequests,theserverpromptsforausernameandpasswordcombination.Thisisfollowedbythebrowserpromptingwithausernameandpasswordentryform.
ConfigureBasicAuthorizationin
servicemix-http
Wewilluseasetofpropertiesfileandconfigurationfilesasshownabove,forsettingupthesecuritysample.
Theservicemix.xmlfilewillhostthemainsecurityconfigurationsasshownhere:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:http="http://servicemix.apache.org/http/1.0"
xmlns:soap="http://servicemix.apache.org/soap/1.0"
xmlns:test="http://binildas.com/esb/servicemix/security">
<importresource="classpath:activemq.xml">
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:security.xml">
<classpath>
<location>.<location>
</classpath>
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<sm:systemProperties>
<propertyname="properties">
<map>
<entrykey="java.security.auth.login.config">
<bean
class="org.springframework.util.ResourceUtils"
factory-method="getFile">
<constructor-argvalue="classpath:basiclogin.
properties">
<bean>
</entry>
</map>
</property>
</sm:systemProperties>
<sm:containerid="jbi"rootDir="./wdir">
<sm:broker>
<sm:securedBroker>
<sm:authorizationMap>
<sm:authorizationMap>
<sm:authorizationEntries>
<sm:authorizationEntryservice=":"
roles="superuser"/>
<sm:authorizationEntryservice="test:echo"
roles="secureuser">
<sm:authorizationEntries>
</sm:authorizationMap>
</sm:authorizationMap>
</sm:securedBroker>
</sm:broker>
<sm:activationSpecs>
<sm:activationSpecid="http">
<sm:component>
<http:component>
<http:endpoints>
<http:endpointservice="test:httpConsumer"
endpoint="httpConsumer"targetService="test:echo"
role="consumer"
locationURI="http://localhost:8192/Service/"
authMethod="basic"defaultMep="http://www.w3.org/
2004/08/wsdl/in-out">
</http:endpoint>
</http:endpoints>
</http:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="echo"
service="test:echo">
<sm:component>
<beanclass="org.apache.servicemix.components.
util.EchoComponent">
<sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
</beans>
Here,forthehttp:endpointelementyoudefinetheHTTPbasicauthenticationbysettingauthMethod="basic".
Wecanalsoplug-inauthorizationintheconfiguration.Forthis,wefirstdefineasecuredbroker(sm:broker)whichcanmatchthebasicHTTPauthenticateduseragainstanAccessControlList(ACL).Toplug-intheACL,wefirstsetthesystempropertieswithkey"java.security.auth.login.config"andvaluepointingtobasiclogin.properties.basiclogin.propertiesisshowninthefollowingcode:
servicemix-domain
{
org.apache.servicemix.jbi.security.login.PropertiesLoginModule
required
debug=true
org.apache.servicemix.security.properties.user="basicusers.
properties"
org.apache.servicemix.security.properties.group="basicgroups.
properties";
};
Thebasicgroups.propertiesdefinesvariousgroupsandmapswhichallusersbelongtowhichallgroups.Thebasicgroups.propertiesisshownhere:
superuser=manager
secureuser=binil
Now,theusercredentialsarestoredinthebasicusers.propertiesandareshownhere:
system=manager
binil=binil
user1=user1
Thesecuredbrokerputstheauthorizationrulesasfollows:
Asadefaultpolicy,letonlythe"superuser"rolebeallowedtoaccessJBIendpoints.
<sm:authorizationEntryservice=":"
roles="superuser"/>
Letuserswithrole"secureuser"beauthorizedtoaccesstest:echoservice.
<sm:authorizationEntryservice="test:echo"
roles="secureuser"/>
DeployandRuntheSampleTobuildtheentiresample,changedirectorytotheBasicHttpfolderandexecutethebuild.xmlfileprovidedasfollows:
cdch17\02_Security\BasicHttp
ant
NowbringtheServiceMixserverupbyexecutingthefollowingcommand:
%SERVICEMIX_HOME%\bin\servicemixservicemix.xml
OnceServiceMixisup,executeClient.htmlfileprovidedagaininthesamefolder,andclickthesendbutton.Thebrowserwillpromptfortheusernameandpasswordentryformwhereyoucanenterthecredentialsbinilandbinilbelongingtothesecureusergrouptoaccesstheservice.
Ifyoutrytoaccesstheservicewithadifferentcredential(forwhichtheACLpermissionisnotgranted),theservicewillnotbeaccessibleforyou.
SampleDemonstratingClusteringThissectionwilldemonstratetheclusteringfeaturesprovidedbyServiceMixwhichwediscussedearlierwiththehelpoftherunningsamples.
SampleUseCaseThesamplescenarioweuseforclusteringwillconsistofthreeServiceMixinstancesconfiguredinacluster.Forthesakeofsimplicity,allthreeinstanceswillcurrentlyruninasinglephysicalnode,henceweareusingthe"localhost"astheserverIPeverywhere.However,itispossibletodistributetheseinstancesintodifferentphysicalnodesinwhichcasewemayhavetousetheIPaddressofthesenodestoformthecluster.
Thefollowingfigureshowstheclustersetup.Here,wehavethreedifferentServiceMixinstances.Sinceinclustermode,alltheServiceMixinstancesmusthaveauniquenameinthewholecluster.Wewillnametheinstanceswithdifferentnamesnamelyadmin,managed1,andmanaged2.OneoftheseServiceMixinstancesalsomanagesaJMSconnectionbroker,andhencewehavearbitrarilynamedthatinstancewiththename"admin".
TheJBIservicescanbedeployedintoanyoftheServiceMix
instancesinthiscluster.Todeployaserviceintothecluster,wewilldeploythoseservicesintoall(ormany)instancesintothecluster.Whenwedoso,allthecontainersintheclusterarenotifiedofthedeployment.NowtheclustercanadministerroutingorloadbalancingpolicieswhenitreceivesclientrequestsbyautomaticallyroutingMessageExchange(s)betweenthemembersofthecluster.Suchserviceswhichwedeployacrossclustersarecalledclusteredservices.WecanalsodeployservicesintoasingleinstanceoftheJBIcontainerintheclusterinwhichcasewecalltheserviceapinnedservice.
Foraclusteredservice,evenifoneoftheServiceMixinstanceshostingtheserviceisdowntheserviceisstillupsincethereareotherclusterinstancestoservetherequest.Howeverforapinnedservicewehavetomakesurethattheserverinstancetowhichtheserviceispinnedshouldbeup,otherwisetheservicewillceasetoserve.
Forthesample(refertothepreviousfigure)wewillmakeuseofbothclusteredandpinnedservices.Asshowninfigure,receiver3isaclusteredservicesinceitisdeployedinboththeinstancesofthecluster.receiver1andreceiver2arepinnedservicessincetheyaredeployedtomanaged1andmanaged2instancesalone,respectively.TheexternalJMSclientwilltargetthemessagestoalltheabovethreeservices.Wecanseethatformessagestargetedtoreceiver1andreceiver2,theyarealwaysroutedtomanaged1andmanaged2serverinstancesrespectively.However,formessagestargetedtoreceiver3theclusterwillloadbalancetherequeststoanyoftheserversinthecluster.Ifbyanychancewebringdownanyofthe
managedservers,thenthepinnedservicesinthatinstancewillnolongerbeavailable,butallthesubsequentrequestsfortheclusteredservicewillthenonwardsberoutedtotheotherinstance(s)oftheserverintheclusteralone.
Thevariousartifactsusedfortheclusteringdemonstrationarearrangedwithindifferentsubfoldersasshowninthedirectorystructureinthefollowingfigure:
ConfigureServiceMixClusterForeachoftheServiceMixserverinstancesparticipatinginthecluster,wehavedifferentserverconfigurationfiles,andlet
uslookatthemonebyone:
Theadminserverconfigurationisincludedinch17\03_Clustering\admin\
servicemixadmin.xml,whichisshowninthefollowingcode.
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:amq="http://activemq.org/config/1.0"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:jms="http://servicemix.apache.org/jms/1.0"
xmlns:foo="http://servicemix.org/demo/">
<beanid="propertyConfigurer"
class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<propertyname="location"
value="classpath:servicemix.properties">
<bean>
<importresource="classpath:jmx.xml">
<importresource="classpath:jndi.xml">
<importresource="classpath:security.xml">
<importresource="classpath:tx.xml">
<importresource="classpath:activemq.xml"/>
<beanid="jndi"
class="org.apache.xbean.spring.jndi.
SpringInitialContextFactory"
factory-method="makeInitialContext"
singleton="true">
<sm:containerid="jbi"name="admin"
flowName="jms?jmsURL=tcp:/localhost:61616"
useMBeanServer="true"createMBeanServer="true"
rmiPort="1111">
<sm:activationSpecs>
<sm:activationSpec>
<sm:component>
<jms:component>
<jms:endpoints>
<jms:endpointservice="test:MyConsumerService"
endpoint="myConsumer"role="consumer"
soap="false"targetService="foo:recipients"
defaultMep="http://www.w3.org/2004/
08/wsdl/in-only"destinationStyle="queue"
jmsProviderDestinationName="queue/A"
connectionFactory="#connectionFactory">
<jms:endpoints>
</jms:component>
</sm:component>
</sm:activationSpec>
<sm:activationSpecid="servicemix-eip">
<sm:component>
<eip:component>
<eip:endpoints>
<eip:static-recipient-list
service="foo:recipients"endpoint="endpoint">
<eip:recipients>
<eip:exchange-targetservice="foo:receiver1">
<eip:exchange-targetservice="foo:receiver2">
<eip:exchange-targetservice="foo:receiver3">
<eip:recipients>
</eip:static-recipient-list>
</eip:endpoints>
</eip:component>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
<beanid="broker"
class="org.apache.activemq.xbean.BrokerFactoryBean">
<propertyname="config"
value="classpath:activemq.xml">
<bean>
<beanid="jmsFactory"
class="org.apache.activemq.pool.PooledConnectionFactory">
<propertyname="connectionFactory">
<refbean="connectionFactory">
<property>
</bean>
<beanid="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<propertyname="brokerURL"
value="tcp://localhost:61616">
<bean>
</beans>
HerewehaveaJMSconsumerthroughwhichtheexternalJMSclientcansendmessagestotheNMR.ThenwehaveconfiguredJMSbrokertobelisteningatlocalhost:61616.Moreover,wehavealsosettheflowtobeoftypeJMSbysettingflowName="jms?jmsURL=tcp://localhost:61616".
Thefirstmanagedserverconfigurationisincludedinch17\03_Clustering\managed1\
servicemixmanaged1.xml,whichislistedinthefollowingcode:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:amq="http://activemq.org/config/1.0"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:foo="http://servicemix.org/demo/">
<classpath>
<location>.</location>
<location>./build</location>
</classpath>
<beanid="jndi"
class="org.apache.xbean.spring.jndi.
SpringInitialContextFactory"
factory-method="makeInitialContext"
singleton="true">
<sm:containerid="jbi"name="managed1"
flowName="jms?jmsURL=tcp:/localhost:61616"
useMBeanServer="true"createMBeanServer="true">
<sm:activationSpecs>
<sm:activationSpeccomponentName="receiver1"
service="foo:receiver1">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="managed1.MyReceiver">
<propertyname="name">
<value>1</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver3"
service="foo:receiver3">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="managed1.MyReceiver">
<propertyname="name">
<value>3</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
</beans>
Herewesetname="managed1"andalsosetflowName="jms?
jmsURL=tcp://localhost:61616".Thenthismanagedserveralsowillformapartofthesameclusterjoinedbytheadminserver.Thenwedeployreceiver1and
receiver3servicestothisserver.
Thesecondmanagedserverconfigurationisincludedinch17\03_Clustering\managed2\
servicemixmanaged2.xml,whichislistedasfollows:
<?xmlversion="1.0"encoding="UTF-8"?>
<beans
xmlns:sm="http://servicemix.apache.org/config/1.0"
xmlns:amq="http://activemq.org/config/1.0"
xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:foo="http://servicemix.org/demo/">
<classpath>
<location>.</location>
<location>./build</location>
</classpath>
<beanid="jndi"
class="org.apache.xbean.spring.jndi.
SpringInitialContextFactory"
factory-method="makeInitialContext"
singleton="true">
<sm:containerid="jbi"name="managed2"
flowName="jms?jmsURL=tcp:/localhost:61616"
useMBeanServer="true"createMBeanServer="true"
rmiPort="1111">
<sm:activationSpecs>
<sm:activationSpeccomponentName="receiver3"
service="foo:receiver3">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="managed2.MyReceiver">
<propertyname="name">
<value>3</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
<sm:activationSpeccomponentName="receiver2"
service="foo:receiver2">
<sm:component>
<beanxmlns="http://xbean.org/schemas/spring/1.0"
class="managed2.MyReceiver">
<propertyname="name">
<value>2</value>
</property>
</bean>
</sm:component>
</sm:activationSpec>
</sm:activationSpecs>
</sm:container>
</beans>
Herethemaindifferenceisthatwesetname="managed2".MoreoverwesetflowName="jms?jmsURL=tcp://localhost:61616"sothatthismanagedservertoowillformapartofthesameclusterjoinedbytheadminandpreviousmanagedserver.Thenwedeployreceiver2andreceiver3servicestothisserver.
Soinanutshell,receiver1andreceiver2arepinnedserviceswhereasreceiver3isaclusteredservice.
DeployandrunthesampleTobuildtheentiresample,itiseasiertochangedirectorytothetop-levelfolderandexecutethebuild.xmlfileprovidedthere:
cdch17\03_Clustering
ant
Thiswillbuildtheentirecodebasefortheclusteringdemonstration.Nowweneedtotakethreedifferentcommandpromptsandbringupalltheserverinstancesinthecluster,inthesameorderasshownasfollows:
cdch17\03_Clustering\admin
%SERVICEMIX_HOME%\bin\servicemix
servicemixadmin.xml
cdch17\03_Clustering\managed1
%SERVICEMIX_HOME%\bin\servicemix
servicemixmanaged1.xml
cdch17\03_Clustering\managed2
%SERVICEMIX_HOME%\bin\servicemix
servicemixmanaged2.xml
Theclustershouldbeupbynow.Nowtotesttheclustersetup,inadifferentcommandpromptexecutethefollowing:
cdch17\03_Clustering
antrun
Keepwatchingontheserver-sideconsoleprintouts,especiallytheconsoleofthemanaged1andmanaged2servers.Executeantrunacoupleoftimesandunderstandhowtheclusterloadbalancesrequeststargetedtothedifferentservices.
Themanaged1serverconsoleisshowninthefollowingscreenshot:
Themanaged2serverconsoleisshowninthefollowingscreeenshot:
Wecanseethattherequestroutedtoreceiver3(whichisaclusteredservice)isloadbalancedwhereastherequestsroutedtoreceiver1andreceiver2(whicharepinnedservices)arealwaysservedbytheirrespectivepinnedservers.
Youmayalsowanttokilloneofthemanagedserversandtrytheeffectofthatonnewincomingrequests.Youcanlaterbringthisdeadserverbacktojointheclusterwithoutdisturbingtheclustersetup.
SampledemonstratingJMX
TodemonstrateJMXinServiceMix,wewillusethesamesampleweusedforChapter9(PojoBindingUsingJsr181).Thesamplech09\Jsr181BindPojoisrepeatedinthischapterandiskeptinfolderch17\04_JMX.
EnableJMXinServiceMixApplicationServiceMixusesthefollowingparameterforenablingJMX:
ThedefaultnamingPort:1099.
Thedefaultcontainername:jmxrmi.
TheJMXServiceURL:service:jmx:rmi:///jndi/rmi://localhost:10
99/jmxrmi.
ThesearethedefaultsettingsforServiceMixversion3.x.Forversion2.x,JMXServiceURLalonechangesto:service:jmx:rmi:///jndi/rmi://localhost:10
99/defaultJBIJMX.
Theabovevaluesareconfiguredthrough%SERVICEMIX_HOME%\conf\jmx.xml.Tostartsimple,editthejmx.xmlfiletodisablethesecurityfeature.Thiscanbedonebyfirstsearchingfor"CommentthefollowinglinestodisableJAASauthenticationfor
jmx"andthencommentingthesucceedinglines.
Now,bringServiceMixup.ThiscanbedonebytryingoutanyofthesamplesinthepreviouschaptersoryoucanusetheJMXsampleprovidedwiththischapter.Todothat,changedirectorytoch17\04_JMXwhichcontainsatop-levelbuild.xmlfile.Executeantthere.
cdch17\04_JMX
ant
Now,bringuptheServiceMixcontainerbyexecutingtheservicemix.xmlfilecontainedinthesamefolder.
%SERVICEMIX_HOME%/bin/servicemixservicemix.xml
InitializeJMXConsole—MC4JYoucanuseanyofyourfavoriteJMXtoolstocontroltheServiceMixapplication.TheJava-2Platform,StandardEdition(J2SE)5.0releaseonwardsincludesaJMXmonitoringtool,JConsole.TobringJConsoleup,executethefollowingcommands:
cd%JAVA_HOME%\bin
jconsole
ForourdemonstrationwewilluseMC4JprovidedbySourceForge.MC4JisthemanagementsoftwareforJ2EEapplicationserversandotherJavaapplications.ItutilizestheJMXspecificationtoconnecttoandintrospecttothe
informationwithinthesupportedserversandapplications.Itprovidestheabilitytobrowsetheexistingmanagedbeans(MBeans),updateconfigurations,monitoroperations,andexecutetasks.
Clickonthe"MC4JConsole1.2b9.exe"filefoundinthetop-leveldirectoryoftheMC4JinstallationtobringuptheMC4Jwindow.ThisMC4Jwindowisshowninthefollowingscreenshot:
SelectManagement|CreateServerConnection...fromthemenu.ThiswillstartMyWizard.AconnectiontoServiceMixcanbecreatedusingthewizard.
Inthewizard,enterthefollowingintothetextboxesandpull-downmenus:
SelectyourserverconnectiontypeasJSR160.
TheNametextboxisfilledwithanyname,forexample,ServiceMix.
SelectServerURLasservice:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi.
AcceptthedefaultsfortherestofthefieldsinthewizardandclicktheNext>button.NowclickFinishinthenextwindow.ThiswillmakeaconnectiontoServiceMix!
Clickonorg.apache.servicemix(1).ThecomponentsofthePOJObindingexamplewillbeshown.Right-clickonacomponentandselectAvailabledashboards...|Basic
MBeanViewtoseetheJMXinformationavailableasshowninthefollowingscreenshot:
RetrieveWSDLthroughJMXAttimeswhenyoutryoutyoursamplesinServiceMixyoumayfeelthatsomethingisnotworkingproperlyorsomeinformationretrievedisnotasperyourexpectation.InsuchscenariositmakessensetomakeuseofaJMXconsoleandlookintothecomponentconfigurations.Letusdoasimilaractivitynow.
InthePOJObindingsampleyouhavealreadywiredtheserviceinterfaceandserviceimplementationasfollows:
<jsr181:endpointannotations="none"
service="test:helloService"
serviceInterface="samples.HelloServiceBI">
<jsr181:pojo>
<beanclass="samples.HelloServicePojo">
</bean>
</jsr181:pojo>
</jsr181:endpoint>
LetusnowloadtheWSDLgeneratedbytheJBIbusbyclickingontheloadWSDLbutton.YoumayhavetounchecktheViewasHTMLcheckboxtomaketheWSDLvisible,whichisshowninthefollowingfigure:
SummaryIhopeyouhaveenjoyedthislastchapter.Thesamplesdemonstratedhere,especiallytheusageoftheJMXtooltolookintotheartifactsinsidethebuswillbehighlyusefulwhen
yourunyourowncomponentsinsidetheServiceMixJBIbus.
Ifyouhavegonethroughallthepreviouschaptersalsointhistext,bynowyoushouldhave"handson"knowledgeofwhatanESBisandwhatJBIhastodoindefiningESB-basedarchitectures.ThiswillgiveyouanedgeoveryourpeersinunderstandingESBandinpreparingyourselvestoleverageESBtosolveyourintegrationproblems.
InmyentirecareerIhaveinteractedwithalotofpeoplewhotalkandwritealotonESBinwhitepapers,buttheynevergavemeanycodetoplayaroundwith.ItisinthiscontextIdecidedtospendafewchaptersonESBwithcode.IhopeyouenjoyedreadingjustasIenjoyedwritingit.