Download Java EE 7 Development with WildFly
Transcript
JavaEE7DevelopmentwithWildFly TableofContents JavaEE7DevelopmentwithWildFly Credits AbouttheAuthors AbouttheReviewers www.PacktPub.com Supportfiles,eBooks,discountoffers,andmore Whysubscribe? FreeaccessforPacktaccountholders InstantupdatesonnewPacktbooks Preface Whatthisbookcovers Whatyouneedforthisbook Whothisbookisfor Conventions Readerfeedback Customersupport Downloadingtheexamplecode Errata Piracy Questions 1.GettingStartedwithWildFly AnoverviewofJavaEEandWildFly WildFlyandEnterpriseApplicationPlatform WelcometoJavaEE7 JavaServerFaces2.2–JSR344 EnterpriseJavaBeans3.2–JSR345 JavaPersistenceAPI2.1–JSR338 ContextsandDependencyInjectionforJavaEE1.1–JSR346 JavaServletAPI3.1–JSR340 JAX-RS,theJavaAPIforRESTfulWebServices2.0–JSR339 JavaMessageService2.0–JSR343 BeanValidation1.1–JSR349 ConcurrencyutilitiesforJavaEE1.0–JSR236 BatchapplicationsfortheJavaPlatform1.0–JSR352 JavaAPIforJSONProcessing1.0–JSR353 JavaAPIforWebSocket1.0–JSR356 NewfeaturesinWildFly Installingtheserverandclientcomponents InstallingJavaSE Testingtheinstallation InstallingWildFly StartingWildFly Connectingtotheserverwiththecommand-lineinterface StoppingWildFly Locatingtheshutdownscript StoppingWildFlyonaremotemachine RestartingWildFly InstallingtheEclipseenvironment InstallingJBossTools Alternativedevelopmentenvironments InstallingMaven Testingtheinstallation Summary 2.YourFirstJavaEEApplicationonWildFly WildFly8coreconcepts TheWildFly8directorylayout Managingtheapplicationserver ManagingWildFly8withthewebinterface Launchingthewebconsole DeployingyourfirstapplicationtoWildFly8 AdvancedEclipsedeploymentoptions Managingdeploymentswiththewebconsole Changingthedeploymentscannerproperties Deployingapplicationsusingthecommand-lineinterface Deployingapplicationstoadomain Summary 3.IntroducingJavaEE7–EJBs EJB3.2–anoverview DevelopingsingletonEJBs ConfiguringtheEJBprojectobjectmodule(pom.xml) CodingourEJBapplication Controllingbeanconcurrency Usingbean-managedconcurrency Cookingsessionbeans Addingastatelessbean Addingastatefulbean DeployingtheEJBapplication CreatingaremoteEJBclient Configuringtheclient’sprojectobjectmodule CodingtheEJBclient AddingtheEJBclientconfiguration Runningtheclientapplication Addinguserauthentication UsingtheEJBtimerservice Programmatictimercreation Schedulingtimerevents AddingasynchronousmethodstoourEJBs Usingfire-and-forgetasynchronouscalls ReturningaFutureobjecttotheclient Summary 4.LearningContextandDependencyInjection IntroducingContextsandDependencyInjection Namedbeans CDIscopes WildFlyCDIimplementation Rethinkingyourticketingsystem Addingtherequireddependencies Creatingthebeans Buildingtheview JSF2facetsuggestions Gettingreadytoruntheapplication Combiningtheschedulerintoourapplication InstallingRichFaces Makingyourapplicationrich Runningtheapplication Creatinginterceptors AreEJBsandJSFManagedBeansobsolete? Summary 5.CombiningPersistencewithCDI Datapersistencemeetsthestandard WorkingwithJPA Addingpersistencetoourapplication Settingupthedatabase InstallingtheJDBCdriverinWildFly Usingthecommand-lineinterfacetocreateanewdatasource CreatingtheMavenproject AddingtheMavenconfiguration Cookingentities AddingBeanValidation Configuringpersistence Addingproducerclasses Codingqueriesforyourapplication Addingservicestoyourapplication Addingacontrollertodriveuserrequests CodingtheJSFview Runningtheexample Summary 6.DevelopingApplicationswithJBossJMSProvider AshortintroductiontoJMS ThebuildingblocksofJMS TheJBossmessagingsubsystem Creatingandusingconnectionfactories UsingJMSdestinations Addingmessage-drivenbeanstoyourapplication Cookingmessage-drivenbeans AddingtheJMSproducer Compilinganddeployingtheapplication Specifyingwhichmessagetoreceiveusingselectors Transactionandacknowledgmentmodes UsingJMStointegratewithexternalsystems Areal-worldexample–HornetQandActiveMQintegration InstallingtheActiveMQresourceadapter ConsumingActiveMQmessages Summary 7.AddingWebServicestoYourApplications DevelopingSOAP-basedwebservices StrategiestobuildSOAP-basedwebservices JBossSOAP-basedwebservicesstack AbrieflookattheJAXWSarchitecture CodingSOAPwebserviceswithWildFly DevelopingaPOJOwebservice Inspectingthewebservicefromtheconsole Testingoursimplewebservice EJB3StatelessSessionBean(SLSB)webservices Developingawebserviceconsumer DevelopingREST-basedwebservices AccessingRESTresources JBossRESTwebservices ActivatingJAX-RS AddingRESTtoourticketexample Addingfilters ConsumingourRESTservice Compilingourticketexample AddingAngularJS ChoosingbetweenSOAPandRESTservices Summary 8.AddingWebSockets AnoverviewofWebSockets HowdoWebSocketswork Creatingourfirstendpoint Expandingourclientapplication TransformingPOJOstoJSON AnalternativetoWebSockets Summary 9.ManagingtheApplicationServer EnteringtheWildFlyCLI LaunchingtheCLI Connectingfromremotehosts UsingaCLIinthegraphicalmode ConstructingCLIcommands Determiningtheresourceaddress Performingoperationsonresources Usingthetabcompletionhelper DeployingapplicationsusingtheCLI DeployingapplicationstoaWildFlydomain Deployingtoallservergroups Deployingtoasingleservergroup CreatingCLIscripts DeployinganapplicationtoseveralWildFlynodes Restartingserversinadomain Installingadatasourceasamodule AddingJMSresources UsingadvancedlanguagestocreatepowerfulCLIscripts UsingscriptinglanguagestowrapCLIexecution UsingtherawmanagementAPItomanagetheapplicationserver ReadingmanagementmodeldescriptionsviatherawmanagementAPI CreatingyourresourcewatchesusingthedetypedAPI Role-basedsecurity Auditingadministrativeoperations Patchingarunninginstance Summary 10.SecuringWildFlyApplications ApproachingtheJavasecurityAPI TheWildFlysecuritysubsystem Settingupyourfirstloginmodule UsingtheloginmoduleintheTicketwebapplication SwitchingtoFORM-basedsecurity CreatingaDatabaseloginmodule Encryptingpasswords UsingtheDatabaseloginmoduleinyourapplication SecuringEJBs Securingwebservices Securingthetransportlayer EnablingtheSecureSocketLayeronWildFly Certificatemanagementtools SecuringtheHTTPcommunicationwithaself-signedcertificate Generatingtheserverandclientcertificates CreatinganSSL-awaresecurityrealm SecuringHTTPcommunicationwithacertificatesignedbyaCA SecuringEJBcommunication ConnectingtoanSSL-awaresecurityrealm Summary 11.ClusteringWildFlyApplications Clusteringbasics WildFlyclustering Startingaclusterofstandalonenodes Startingaclusterofdomainnodes Thedomaincontrollerconfiguration Hostconfigurations Deployingclusteredapplications CreatingHAStatefulSessionBeans ClusteringtheTicketexample Turningyourcacheintoadistributedcache Codingthecluster-awareremoteclient Deployingandtestinghighavailability Webapplicationclustering Loadbalancingyourwebapplications Installingmod_cluster Clusteringyourwebapplications ProgrammingconsiderationstoachieveHA AchievingHAinJSFapplications Summary 12.Long-termTasks’Execution Theoverviewofthebatchingframework Ourfirstbatchjob Creatingachunk-basedbatchstep Creatingajob-basedbatchstep UsingconcurrencyutilitiesinJavaEE Introducingthreadstoenterprisebeans Summary 13.TestingYourApplications Testtypes Instrumentsusedfortesting GettingstartedwithArquillian WritinganArquilliantest Configuringthepom.xmlfile WritingyourfirstArquilliantest RunningArquillianTicketTest RunningArquilliantestsusingSpock ShrinkWrapResolver ShrinkWrapDescriptors Persistencetesting ArquillianWarp WebSocketstesting EnhancingyourArquilliantest Additionalinformation Summary A.RapidDevelopmentUsingJBossForge InstallingForge StartingForge CreatingyourfirstJavaEE7applicationwithJBossForge Buildinganddeployingtheapplication YourForge-demoapplicationinaction Index JavaEE7DevelopmentwithWildFly JavaEE7DevelopmentwithWildFly Copyright©2014PacktPublishing Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem, ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthe publisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews. Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyofthe informationpresented.However,theinformationcontainedinthisbookissoldwithout warranty,eitherexpressorimplied.Neithertheauthors,norPacktPublishing,andits dealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecaused directlyorindirectlybythisbook. PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthe companiesandproductsmentionedinthisbookbytheappropriateuseofcapitals. However,PacktPublishingcannotguaranteetheaccuracyofthisinformation. Firstpublished:June2013 Secondedition:December2014 Productionreference:1241214 PublishedbyPacktPublishingLtd. LiveryPlace 35LiveryStreet BirminghamB32PB,UK. ISBN978-1-78217-198-0 www.packtpub.com CoverimagebyMichaelJasej(<[email protected]>) Credits Authors MichałĆmil MichałMatłoka FrancescoMarchioni Reviewers DustinKutMoyCheung AdamDudczak MaximeGréau BartoszMajsak JakubMarchwicki CommissioningEditor JamesJones AcquisitionEditor JamesJones ContentDevelopmentEditor MohammedFahad TechnicalEditors IndrajitA.Das RohitKumarSingh CopyEditors GladsonMonteiro AdithiShetty ProjectCoordinator AkashPoojary Proofreaders TingBaker SimranBhogal AmeeshaGreen Indexers RekhaNair PriyaSane ProductionCoordinator ShantanuN.Zagade CoverWork ShantanuN.Zagade AbouttheAuthors MichałĆmilisaJavadeveloperwithexperienceinwebanddesktopapplication development.Inthepast,hehasworkedforthee-commercesector.Currently,heis developingmanufacturingexecutionsystemsforindustryclients.Hehasbeenavolunteer atGeeCON.Michałworksasasoftwaredesigner/developerforPSIPoland. MichałMatłokaisaJavadeveloperwithexperienceinbothJavaEEandSpring technologies.HeisaJBosscommunitycontributor,focusingmainlyonArquillianand ShrinkWrap,andisalsoawinneroftheJBossCommunityRecognitionAwardin2013for hiscontributionstoShrinkWrap.HehasspokenatPoznanJavaUserGroupand volunteeredatGeeCON.Michałiscurrentlyoneofthe20CEOsatSoftwareMill,afully distributedcompanywithnomainofficeandacompletelyflatorganizationstructure. FrancescoMarchioniisaSunCertifiedEnterprisearchitectemployedforanItalian companybasedinRome.HestartedlearningJavain1997,andsincethenhehasfollowed thepathtothenewestApplicationProgramInterfacesreleasedbySun.In2000,hejoined theJBosscommunitywhentheapplicationserverwasrunningthe2.xrelease. Hehasspentmanyyearsasasoftwareconsultant,wherehehasenvisionedmany successfulsoftwaremigrationsfromvendorplatformstotheopensourceproductssuchas JBossAS,fulfillingthetightbudgetrequirementsofcurrenttimes. Forthepast5years,hehasbeenauthoringtechnicalarticlesforO’ReillyMediaandalso runsanITportalfocusedonJBossproducts(http://www.mastertheboss.com). InDecember2009,heauthoredJBossAS5Development,PacktPublishing,which describeshowtocreateanddeployJavaEnterpriseapplicationsonJBossAS. InDecember2010,heauthoredhissecondtitle,JBossAS5PerformanceTuning,Packt Publishing,whichdescribeshowtodeliverfastandefficientapplicationsonJBossAS. InDecember2011,heauthoredyetanothertitle,JBossAS7ConfigurationDeployment Administration,PacktPublishing,whichcoversalltheaspectsofthenewestapplication serverrelease. InAugust2012,hecoauthoredthebook,InfinispanDataGridPlatform,Packt Publishing,withManikSurtani,whichcoversallaspectsrelatedtotheconfigurationand developmentofapplicationsusingtheInfinispandatagridplatform. I’dliketothankPacktPublishingforsharingthevisionofthisnewbookandforallthe efforttheyputinit.I’dalsoliketothankmyfamilyforbeingalwaysonmyside, particularly,mywifeforallowingmetofollowmybookauthorambitions,andmyfather forbuyingmeaC-64insteadofamotorcyclewhenIwasyoung. AbouttheReviewers DustinKutMoyCheungwasbornandraisedintheislandofMauritius.Hisinterestin computerswassparkedwhenhegothisfirstcomputerattheageofnine.Hewentonto studyElectricalEngineeringatMcGillUniversityinMontreal,Canada.Dustiniscurrently workingasaproductizationengineerintheJBossproductizationteamatRedHat. Iwouldliketothanktheauthorsforgivingmetheopportunitytobeoneofthereviewers forthisbook.JavaEE7hascertainlymadewebdevelopmentinJavaeasierandmore elegant.UsingtheWildflyapplicationserverwillenableuserstofullyunlockallthe capabilitiesthatJavaEEhastoofferwhileprovidingeasyadministration,configuration, deployment,clustering,andmuchmore! AdamDudczakisanexperiencedsoftwareengineerworkingwithJavaandrelated technologiessince2004.Heisinterestedinthecreationoflightweight,bulletproof,and scalableapplications.Hehasastrongbackgroundininformationretrievalandtextmining. Currently,heisworkingonabettersearchexperienceinoneofthemajoreastEuropeanecommerceportals.HeisoneoftheleadersofPoznańJUG(http://www.jug.poznan.pl)and aco-organizeroftheGeeCONconference(http://geecon.org).Adamisafatherand husbandandoccasionallyblogsathttp://dudczak.info/dry.HisTwitterhandleis@maneo. MaximeGréauhasbeenbuildingsoftwareprofessionallyforabout12years,mostlyfor theWebandmostofitwithJava.HewroteaFrenchbookaboutApacheMaven3in2011. HecurrentlyworksasaJavaEEarchitect. MaximeisaspeakeratconferencesonJavaandwebtechnologiessuchasDevNationand DevFest.Heisalsoatechnicalreviewer. Heblogsathttp://mgreau.com/blog/andcanbefoundonTwitterandGitHubat@mgreau. BartoszMajsakworksasasoftwaredeveloperatCambridgeTechnologyPartners,based inZurich.Heispassionateaboutopensourcetechnologiesandtestingmethodologies.He isaproudJBossCommunityRecognitionawardrecipientfor2012and2013.He’salsoan Arquillianteammemberandtheleadfortwomodules:PersistenceExtension(makes writingdatabase-orientedtestseasier)andSpockTestRunner(givesyourArquilliantests someBDDandGroovylove).OnethingthatperhapsprovesBartoszisnotatotalgeekis hisaddictiontoalpineskiing. JakubMarchwickihasbeeninthesoftwaredevelopmentindustryforthepast10years— wearingmultiplehats,gettinghishandsdirtyinmultipleenvironments,andsecuringboth technicalaswellasthebusinesssideofTheThing,whichisanengineerwithahumanfriendlyinterface.Additionally,hehasworkedwithavarietyoflanguagesand frameworks. Jakubhasalwaysconsideredprogrammingatooltosolvereal-lifeproblemsina pragmaticway.Hehasalwaysstayedclosetothebusinesssideofthesolution,focusing onthetechnology.Hecombineshisdailyjobofmanagingahordeofsoftwareengineers atYoungDigitalPlanetwithlectures,technicaltrainings,andcommitmenttoGdańskJava UserGroup. www.PacktPub.com Supportfiles,eBooks,discountoffers,and more Forsupportfilesanddownloadsrelatedtoyourbook,pleasevisitwww.PacktPub.com. DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFand ePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandas aprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwith usat<[email protected]>formoredetails. Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signup forarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooks andeBooks. https://www2.packtpub.com/books/subscription/packtlib DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigital booklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks. Whysubscribe? FullysearchableacrosseverybookpublishedbyPackt Copyandpaste,print,andbookmarkcontent Ondemandandaccessibleviaawebbrowser FreeaccessforPacktaccountholders IfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccess PacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsfor immediateaccess. InstantupdatesonnewPacktbooks Getnotified!Findoutwhennewbooksarepublishedbyfollowing@PacktEnterpriseon TwitterorthePacktEnterpriseFacebookpage. Preface WildFly,thenewestreleaseoftheJBossApplicationServer,providesdeveloperswitha fullimplementationoftheJavaEE7platform.Itisbuiltonsolidfoundationsofthe modulararchitectureintroducedwithJBossAS7,butithasgrownintermsofflexibility andperformance.ThenewestversionoftheEnterpriseJavafocusesondevelopers’ productivity,andsodoesWildFly. ThisbookwillintroduceJavadeveloperstotheworldofenterpriseapplications.Wewill usemoderndevelopmenttechniquesandtoolsthatarebattle-testedinreal-lifeprojects. We’llalsoutilizethefeaturesprovidedbytheWildFlyplatform,suchassecurity,caching, testing,andclustering.Finally,youwilllearnhowtomanageyourserverusingdedicated tools,createdspecificallyforWildFly. Thelearningprocesswillbeconcentratedaroundaticketbookingapplication,whichisa sampleprojectthatwillgetmorefeatures(andsometimescompletelydifferentuser interfaces)witheverychapter. Whatthisbookcovers Chapter1,GettingStartedwithWildFly,isanintroductiontotheJavaEEplatformand newJavaEE7versionspecifications.ItalsofocusesonpresentingWildFly’snew features,thedeveloperenvironmentsetup,andbasicservermanagement. Chapter2,YourFirstJavaEEApplicationonWildFly,describesthebasicsoftheWildFly serverusage,presentinginformationrequiredtodeployyourfirstapplication. Chapter3,IntroducingJavaEE7–EJBs,introducesJavaEEbusinessobjectscalled EnterpriseJavaBeans.Inthischapter,wecreatethefoundationsoftheticketbooking application. Chapter4,LearningContextandDependencyInjection,coverstheCDItechnologythat connectsthebuildingblocksofyourapplications. Chapter5,CombiningPersistencewithCDI,isalookintothedatabaseworldandobject mappinginJavaEE. Chapter6,DevelopingApplicationswithJBossJMSProvider,isadiveintoHornetQand enterprisesystemintegrationusingJCA. Chapter7,AddingWebServicestoYourApplications,discussesnotonlytheold-style SOAPwebservicesbutalsothemodernandpopularapproachbasedonJAX-RS(REST). We’llalsotakealookathowtointegrateaJavaEE7backendwithanAngularJSbrowser application. Chapter8,AddingWebSockets,introducesacompletelynewassettotheJavaEE7 platform:WebSockets.WewilllookattheminoursampleAngularJSapplication. Chapter9,ManagingtheApplicationServer,discussesWildFlymanagementfeatures. Chapter10,SecuringWildFlyApplications,focusesonsecurity-relatedaspectsofthe serverandyourapplication. Chapter11,ClusteringWildFlyApplications,discussesmakingJavaEEapplications highlyavailableandscalable. Chapter12,Long-termTasks’Execution,describesthenewareaofenterpriseJavabatch applicationsandconcurrencymanagementontheserver. Chapter13,TestingYourApplications,demonstrateshowwecanwriteintegrationtestsfor forourapplicationsusingArquillianaftercoveringthemostimportantJavaEE technologies. Appendix,RapidDevelopmentUsingJBossForge,coverstheJBossForgetool.Itshows howyoucanusethisapplicationtospeedupyourworkwithitscodegenerationfeatures onstartingJavaEE-basedprojects. Whatyouneedforthisbook Thisbookisacode-orientedguideintotheJavaEEandWildFlyworlds.Tofullybenefit fromthisbook,youwillneedaccesstoanInternetconnectioninordertodownloadallthe requiredtoolsandlibraries.KnowledgeofJavaisrequired.WewillalsouseMavenasa buildautomationtool,butthankstoitsverbosity,theexamplesprovidedinthisbookare self-explanatory. AlthoughwewilluseAngularJS,additionalJSknowledgeisnotrequired.Allexamples fortheframeworkwillbeshowcase-based,andtheiraimistoshowhowdifferentparties caninteractwithJavaEEintypicalscenarios. Whothisbookisfor IfyouareaJavadeveloperwhowantstolearnaboutJavaEEbasicsorifyouarealreadya JavaEEdeveloperwhowantstolearnwhat’snewinWildFlyorJavaEE7,thisbookis foryou.Thisbookcoversbasicsofthedescribedtechnologiesandalsoensurestobring somemoreinteresting,advancedtopicsforthosewhoalreadyhavesomeknowledge. Conventions Inthisbook,youwillfindanumberofstylesoftextthatdistinguishbetweendifferent kindsofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheir meaning. Codewordsintext,databasetablenames,foldernames,filenames,fileextensions, pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“Afteran MDBinstance’sonMessage()methodreturns,therequestiscomplete,andtheinstanceis placedbackinthefreepool.” Ablockofcodeissetasfollows: <jms-destinations> <jms-queuename=“TicketQueue”> <entryname=“java:jboss/jms/queue/ticketQueue”/> <durable>false</durable> </jms-queue> </jms-destinations> Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevant linesoritemsaresetinbold: @Stateless publicclassSampleEJB{ @Resource(mappedName=“java:/ConnectionFactory”) privateConnectionFactorycf; } Anycommand-lineinputoroutputiswrittenasfollows: CREATEDATABASEticketsystem; CREATEUSERjbossWITHPASSWORD‘jboss’; GRANTALLPRIVILEGESONDATABASEticketsystemTOjboss; Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,in menusordialogboxes,forexample,appearinthetextlikethis:“Forexample,the Eclipse’sFilemenuincludesanoptionJPAEntitiesfromTablethat(onceaconnection hasbeensetuptothedatabase)allowsreversingyourDBschema(orpartofit)intoJava entities.” Note Warningsorimportantnotesappearinaboxlikethis. Tip Tipsandtricksappearlikethis. Readerfeedback Feedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthis book—whatyoulikedormayhavedisliked.Readerfeedbackisimportantforusto developtitlesthatyoureallygetthemostoutof. Tosendusgeneralfeedback,simplysendane-mailto<[email protected]>,and mentionthebooktitleviathesubjectofyourmessage. Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingor contributingtoabook,seeourauthorguideatwww.packtpub.com/authors. Customersupport NowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelp youtogetthemostfromyourpurchase. Downloadingtheexamplecode YoucandownloadtheexamplecodefilesforallPacktbooksyouhavepurchasedfrom youraccountathttp://www.packtpub.com.Ifyoupurchasedthisbookelsewhere,youcan visithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlyto you. Errata Althoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdo happen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthe code—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveother readersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufind anyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata, selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthe detailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedand theerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataunderthe Erratasectionofthattitle. Toviewthepreviouslysubmittederrata,goto https://www.packtpub.com/books/content/supportandenterthenameofthebookinthe searchfield.TherequiredinformationwillappearundertheErratasection. Piracy PiracyofcopyrightmaterialontheInternetisanongoingproblemacrossallmedia.At Packt,wetaketheprotectionofourcopyrightandlicensesveryseriously.Ifyoucome acrossanyillegalcopiesofourworks,inanyform,ontheInternet,pleaseprovideuswith thelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy. Pleasecontactusat<[email protected]>withalinktothesuspectedpirated material. Weappreciateyourhelpinprotectingourauthors,andourabilitytobringyouvaluable content. Questions Youcancontactusat<[email protected]>ifyouarehavingaproblemwithany aspectofthebook,andwewilldoourbesttoaddressit. Chapter1.GettingStartedwithWildFly JavaEnterpriseEditionprovidesastandardtodevelopenterprisesoftware,butallowsthe developerstochooseitsspecificimplementation.Foreverytechnologythatisincludedin theJavaEE(EnterpriseEdition)specification,thereisareferenceimplementation;an opensourcelibraryorcomponentthatfulfillsalloftherequirements.Companiesand organizationscancreatetheirownversionsofthecomponents,whichmeansthatthereis nocentralJavaEEplatformthateverybodyuses.Inplaceofthat,wegetmultiple approachesontheimplementedspecification,withimprovementsandoptimizationsfor specificcases.Atthetimeofwritingthis,thereareabout20certified(full) implementationsofJavaEE6andthreeimplementationsofJavaEE7. AnapplicationserverisaruntimeenvironmentthatprovidesapplicationswithalltheJava EEcomponents.GlassfishisthereferenceimplementationsponsoredbyOracle,but beginningfromVersion4(createdforJavaEE7),thereisnolongercommercialsupport forit.Inthisbook,youwilllearnhowtodevelopapplicationsontheWildFlyApplication Server,previouslyknownastheJBossApplicationServer. JBossisadivisionofRedHat,whichseekstoprovideadeveloper-friendlyopensource ecosystemforenterprisedevelopment.Currently,thecompanysupportsmultipleprojects (around100),andsomeofthemareimplementationsofJavaEEspecifications.The enterpriseelementsarecombinedinJBoss’sownapplicationserver,WildFly. ItisworthnotingthatthenamechangefromJBossAStoWildFlywasmadetoseparate theapplicationserverfromthecompanyandothersubprojects.Thenamewaschosenina publicvote(moreinformationonthisisavailableathttp://jbossas.jboss.org/rename/vote). ThenewreleasefeaturesascalableandhighperformingwebservercalledUndertow, whichsupportstheHTTPupgrademechanismandWebSocketprotocol.What’smore,the newversionofthecontainerisevenfasterthanJBossApplicationServer7,andoffersa unifiedconfigurationmechanism.However,themainessenceofthelatestreleaseisthe JavaEE7compliance,whichallowsdeveloperstousetechnologiesfromthenewest versionoftheJavaEEspecification. Thefocusofthisbookisonapplicationdevelopment;therefore,wewillfirstneedto gatherallresourcesrequiredtodeliverourapplications.Inthischapter,wewillcoverthe followingtopicsindetail: AnoverviewofJavaEEandWildFly Preparingyourenvironmentfortheinstallationofsoftware DownloadingandinstallingWildFly VerifyingtheWildFlyinstallation Installingotherresourcesneededfordevelopment AnoverviewofJavaEEandWildFly JavaEE(formerlycalledJ2EE)isanumbrellaspecificationembracingastandardsetof technologiesforserver-sideJavadevelopment.JavaEEtechnologiesincludeJavaServlet, JavaServerPages(JSPs),JavaServerFaces(JSFs),EnterpriseJavaBeans(EJB), ContextsandDependencyInjection(CDI),JavaMessagingService(JMS),Java PersistenceAPI(JPA),JavaAPIforXMLWebServices(JAX-WS),andJavaAPIfor RESTfulWebServices(JAX-RS),amongothers.ThenewestversionofJavaEEextends therangeofavailabletechnologiesevenfurtherbyprovidingsupportforBatch Applications,ConcurrencyUtilities,JSONProcessing(JSON-P)andWebSocket. Severalcommercialandopensourceapplicationserversexist,whichallowdevelopersto runapplicationscompliantwithJavaEE;WildFly(formerlyknownasJBossAS)isthe leadingopensourcesolutionadoptedbydevelopersand,althoughthisisdifficultto measureinexactterms,itislikelytobethemostwidelyusedapplicationserverinthe market. AswithallapplicationserverscompliantwithJavaEE,WildFlyshipswithallthe requiredlibrariestoallowustodevelopanddeployJavaapplicationsthatarebuiltonthe JavaEEplatform. WildFlyandEnterpriseApplicationPlatform WildFlyandpreviousJBossApplicationServerswerefreelyavailableforthecommunity intheformofdownloadablebinarypackages(formajorreleases)orbuildablesourcecode (forbugfixingreleases).Theseversionsarecalledcommunityreleasesandarefreetouse fordevelopmentandproduction. JBossalsoreleasesmorestableandhardenedversionsofsoftwareofthecommunity builds,whicharecalledEnterpriseApplicationPlatform(EAP),acommercialproduct withsupportservicefromRedHat.RedHatcallsthiskindofrelationshipbetween projectsasupstream/downstream.Thecommunitybuildsarethesourceofchangesand innovationsforthedownstream,thecodeisdownstream.Thecommercialversion numerationdifferedfromthecommunityline,butitwasanextendedvariantofthe communityreleases(forexample,EAP6.1.0wasbuiltonJBoss7.2.0,whichwas availableonlyonGitHubintheformofbuildablesourcecode;thesamegoesforEAP 6.2.0andJBoss7.3.0).EAPbuildshaveamorecomplexlicensingsystem;theusage termsdependonthematurityofthebuildandareasfollows: EAPAlphaisfreeforthedevelopersandproductionuse,astheyareanequivalentof thestandardcommunityversionwithoptionalfixesincluded.Thecorresponding communitybinariesmaynotbeavailablefordownload,astheywouldbesimilarto theEAPAlphaversion. EAPBetaisavailabletodevelopersforfree(afterregistrationtoasubscription program),butcannotbeusedinproduction. EAPFinalisalsoavailabletodevelopersforfree,butadditionally,newsecurity patchesareavailableonlyinthepaidsubscription. ThedistributionmodelproposedbyJBossallowsthedeveloperstoworkforfreeonthe sameversionastheoneusedinproduction.Thisisahugebenefit,especiallysincethe competitivesolutionfromOracle(Glassfish:thereferenceimplementationofaJavaEE compliantserver)nolongerhasaversionwithcommercialsupport. WelcometoJavaEE7 JavaEE7includesseveralimprovementsandadditionstotheexistingversion.Thenew versionisfocusedonthreethemes:developerproductivity,HTML5,andprovidingnew featuresrequiredbyenterpriseapplications.Thefollowingsectionslistthemajor improvementstothespecificationsthatareofinteresttoenterpriseapplicationdevelopers. IfyouarestartingyouradventurewithJavaEE,feelfreetoskipthissection.The technologiesdescribedinthefollowingsectionswillbecoveredinfuturechaptersinmore detail. JavaServerFaces2.2–JSR344 JavaEE7includesanewversionoftheJSFspecification,whichisnotsorevolutionaryas 2.0,butstillprovidessomeappealingadditionsfordevelopers.Thekeyfeaturesdelivered byJSF2.2areasfollows: TheHTML5markupisnowsupportedbytheusageofpass-throughelementsand attributes.Earlier,customattributeswouldhavetobesupportedbyanextended rendererforeverycomponent.Thenewconstructsallowthedevelopertopass additionalHTMLattributestothemarkupgeneratedbyJSFcomponents. Theflowscopehasbeenintroducedwith@FlowScoped,whichmakesthecreationof wizards(dialogswithmultiplesteps)easier. TheAjax-basedfileuploadisnowsupportedoutofthebox. Also,statelessviewshavebeenpresentedasawaytoimproveperformance. EnterpriseJavaBeans3.2–JSR345 ComparedtoEJB3.1,theVersion3.2isaminorupdateoftheexistingversion.It concentratesmainlyonmarkingsomeolderfeaturesasobsolete(theyarenowoptional, whichmeansthatnoteveryJavaEE7-compliantapplicationserverwillsupportthem). TheoptionalfeaturesareconnectedwithpersistencetowebservicesbasedonEJB2.1and JAX-RPC.Themainenhancementsprovidedbythenewspecificationareasfollows: Lifecyclemethodsforstatefulsessionbeanscannowbetransactional. TheTimerServiceAPI,nowallowsyoutoaccessallactivetimersinthecurrentEJB module. Anewcontainerprovidedrole(**)hasbeenintroduced.Itcanbeusedtoindicate anyauthenticateduser(withouttakinghisorheractualrolesintoaccount). Passivationofstatefulsessionbeanscannowbedisabled. TransactionalpartsoftheEJBspecificationhavebeenextractedandreusedinotherparts oftheJavaEEplatform(thetransactionsupporthasbeenplacedintheJTA1.2 specification).Forinstance,thetransactionalbehaviorcannowbeusedinCDIbeans, thankstotheintroductionofthe@Transactionalannotation. JavaPersistenceAPI2.1–JSR338 JPAwasintroducedasastandardpartofJavaEEinVersion5ofthespecification.JPA wasintendedtoreplaceentitybeansasthedefaultobject-relationalmappingframework forJavaEE.JPAadoptedideasfromthird-partyobject-relationalframeworks,suchas HibernateandJDO,andmadethemapartofthestandardversion. JPA2.1isanimprovementoverJPA2.0asitprovidesseveralfacilitiesfordevelopers, whichareasfollows: Itprovidesastandardizedschemagenerationmechanism,thankstoanextendedset ofannotationsandpersistence.xmlproperties Itaddssupportfortypeconversion,bytheintroductionofthe@Converterannotation StoredproceduresarenowsupportedbytheEntityManagerAPI,sothattheuseof theSQLquerymechanismforthemisnolongerrequired CriteriaAPIhasbeenextendedbybulkupdatesanddeletes Injectionispossibleintoentitylistenerclassesalongwiththeusageoflifecycle callbackmethods Namedqueriescannowbecreatedduringruntime TheJPAQueryLanguage(JPQL)hasbeenextendedwithnewdatabasefunctions Additionally,JavaEE7-compliantcontainersmustnowsupportpreconfigureddata sources(alongwithotherresources),whichcanbeinstantlyusedbyJPAentities. WildFlyusesHibernateasitsJPAproviderandisshippedwithaready-to-useH2inmemorydatabase.ThedefaultdatasourcepointstotheH2instancehostedinsideofthe applicationserver. ContextsandDependencyInjectionforJavaEE1.1–JSR346 Version1.1ofContextsandDependencyInjection(CDI)providesimprovementsfor theissuesidentifiedinCDIafteritsintroductioninJavaEE6.Theprocessofsimplifying theprogrammingmodelstartedinVersion1.0andisnowbeingcontinued.Theareas coveredbytheupdateareasfollows: CDIisnowenabledbydefault(withouttheneedtoaddthebean.xmlfiletothe deployment),withthepossibilitytospecifythedesiredcomponentscanningmode. Morefine-grainedcontroloverthebeandiscoverymechanismisnowavailablefor thedeveloper,thankstotheuseofthe@Vetoedannotationandclassorpackages filtersinbeans.xml.Interceptors,decorators,andalternativescannowbeglobally enabledforthewholeapplicationusingthe@Priorityannotation,insteadof enablingeverymodule. EventmetadatacannowbeexaminedwhenaCDIeventishandled. Interceptorshavebeenenhancedwiththepossibilitytobeexecutedaround constructorinvocation. Finally,thenewversioncontainsasignificantnumberofenhancementsforthe developmentofportableextensions. WeldistheCDIimplementationinternallyusedinWildFly. JavaServletAPI3.1–JSR340 ThenewversionoftheJavaServletAPIhasaclearfocusonnewfeatures.Themost importantofthemistheHTTPupgrademechanism,whichallowstheclientandserverto startaconversationinHTTP1.1,andnegotiateanotherprotocolforsubsequentrequests. ThisfeaturewasusedtoimplementtheWebSocketsmechanisminJavaEE7.Other featuresofthenewversionofspecificationareasfollows: Non-blockingI/OAPIforServletshasbeenprovidedtoimprovescalabilityofweb applications Multiplesecurityimprovementshavebeenintroduced;themostnotableofthemis thepossibilitytosetthedefaultsecuritysemanticsforallHTTPmethods JAX-RS,theJavaAPIforRESTfulWebServices2.0–JSR339 InJavaEE7,theJAX-RSspecificationhasbeenenrichedwithsomelong-awaited features.Theversionhaschangedfrom1.1to2.0becauseofthemajorimpactofthe improvementsthatcamewiththenewspecification.Themostimportantfeaturesarelisted asfollows: TheclientAPIisnowpartofthespecification,sotheusageofthird-partylibrariesis nolongerneeded.Theimplementationofthespecificationisrequiredtoprovidea RESTclientthatconformstothecommonAPI. Asynchronousrequestsarenowsupportedsothattheclientdoesnothaveto passivelywaitforthecompletionofthetask. Filtersandhandlershavebeenintroducedasacommonmechanismtoprovide extensionpointsforthedeveloper.Theycanbeusedforcross-cuttingconcerns,such asauditingandsecurity. BeanValidationhasbeenintegratedintoJAX-RS,makingconstraintannotations usableforrequestparameters. WildFlycomesbundledwithRESTEasy,animplementationofJAX-RS2.0. JavaMessageService2.0–JSR343 TheJSR343isthefirstupdatefortheJMSspecificationinoveradecade.Oncemore,the mainthemeoftheupdateisthesimplificationoftheAPI.ThenewAPIdramatically decreasestheamountofboilerplatecodethathastobewrittenbytheprogrammerwhile stillmaintainingbackwardscompatibility.Othernewfeaturesarelistedasfollows: Asynchronousmessagesendingisnowsupported,sotheapplicationdoesnothaveto beblockeduntilanacknowledgmentfromtheserverisreceived Messagescannowbesentwithascheduleddelayforthedelivery HornetQistheJMSproviderusedanddevelopedbyJBoss.Itispossibletouseitoutside ofWildFlyasastandalonemessagebroker. BeanValidation1.1–JSR349 TheprocessofupdatingtheBeanValidationinJavaEE7concentratesontwomain features: Methodsvalidation,whichallowsthedevelopertovalidateparametersandreturn values TighterCDIintegration,whichchangesthelifecycleoftheelementsofthe validationframework,allowingthedevelopertousedependencyinjectioninhisor herownConstraintValidatorimplementations ConcurrencyutilitiesforJavaEE1.0–JSR236 ConcurrencyutilitiesisanewfeaturepacktousemultithreadinginJavaEEapplication components.ThenewspecificationprovidesManagedExecutorService(acontainer-aware versionofExecutorServiceknownfromJavaSE),whichcanbeusedtodelegatethe executionoftaskstoaseparatethread.Thesemanagedtaskscouldusemostofthe featuresthatareavailableforapplicationcomponents(suchasEJBsorServlets).Itisalso possibletoschedulecyclicordelayedtasksusingnew ManagedScheduledExecutorService.Thesenewadditionstotheplatformarefillinga functionalgapforJavaEE,whichwasveryhardtoovercomewithinitsarchitecture earlieron. BatchapplicationsfortheJavaPlatform1.0–JSR352 Batchjobswereanotherareaofenterpriseapplicationdevelopment,whichwasnot coveredbyearlierversionsofJavaEE.Thenewbatchprocessingframeworkisusedto provideacommonsolutiontoruntasksthatareexecutedwithoutuserinteraction.JavaEE providesthedeveloperwiththefollowingoptions: Batchruntimefortheexecutionofjobs Ajobdescriptionlanguage(basedonXML) TheJavaAPIfortheimplementationofthebusinesslogicforthebatchtasks jBeret,whichisthebatchingframeworkusedinWildFly JavaAPIforJSONProcessing1.0–JSR353 JavaEE7nowcomeswithout-of-the-boxJSONprocessing,sothedeveloperisnolonger forcedtouseexternallibrariesforthistask.ThenewAPIallowsJSONprocessingtouse twoapproaches:objectmodel(DOMbased)andstreaming(event-based). JavaAPIforWebSocket1.0–JSR356 TofullysupportthedevelopmentofapplicationsbasedonHTML5,JavaEE7requiresa standardizedtechnologyfortwo-waycommunicationbetweentheserverandtheuser’s browser.TheWebSocketAPIallowsthedevelopertodefineserver-sideendpoints,which willmaintainaTCPconnectionforeveryclientthatwillconnecttothem(using,for instance,aJavaScriptAPI).Beforethenewspecification,developershadtousevendor- specificlibrariesandnotportablesolutionstoachievethesamegoal. NewfeaturesinWildFly TheeighthreleaseofWildFlyisbasedonmodulararchitectureintroducedintheprevious releasenamedJBossAS7.Ithasimprovedonseveralkeypoints,includingareasof performanceandmanagement.Themostimportantchangeforthedevelopersisthatthis releaseimplementstheJavaEE7standardcompletely.Someofthemostnotable improvementsincludethefollowing: WildFly8implementsallstandardspresentedbyJavaEE7specifications,whichare alsodescribedinthischapter. ThewebservermodulewascompletelyrewrittenunderthenameUndertow.It supportsbothblockingandnon-blockingoperations.Earlyperformancetests(for example,http://www.techempower.com/benchmarks/#section=datar6&hw=i7&test=plaintext)showmajorperformanceimprovementsinHTTPrequest handling.Undertowisalsoavailableasaseparateprojectandispossibletobeused withoutWildFly. ThefinalWildFlyreleasehasreducedthenumberofusedports.Now,itusesonly twoofthem,one(9990)formanagement,JMX,andwebadministration,andthe secondone(8080)forstandardservices,includingHTTP,WebSockets,remoteJNDI, andEJBinvocations. Now,itispossibletolimitauser’smanagementpermissionsusingtheManagement rolebasedaccesscontrol(RBAC).Allconfigurationchangescanbetrackedusing theauditlog. Forpreviousreleases,anyupgradeoperationrequiresacompletelynewserver installation.WildFlybringsthepatchingfeature,allowingtoinstallandrollback modulesusingmanagementprotocols. Inthenextsection,wewilldescribealltherequiredstepstoinstallandstartanew applicationserver. Installingtheserverandclientcomponents Thefirststepinlearningabouttheapplicationserverwillbetoinstallallthenecessary componentsonyourmachineinordertorunit.Theapplicationserveritselfrequiresjusta JDKenvironmenttobeinstalled. Asfarashardwarerequirementsareconcerned,youshouldbeawarethattheserver distribution,atthetimeofwritingthis,requiresabout130MBofharddiskspace,and allocatesaminimumof64MBandamaximumof512MBforastandaloneserver. Inordertogetstarted,wewillneedtogooverthischecklist: InstallJDKwhereWildFlywillrun InstallWildFly InstalltheEclipsedevelopmentenvironment InstalltheMavenbuildmanagementtool Attheendofthischapter,youwillhavealltheinstrumentstogetstartedwiththe applicationserver. InstallingJavaSE ThefirstmandatoryrequirementistoinstallaJDK8environment.TheJavaSEdownload sitecanbefoundat http://www.oracle.com/technetwork/java/javase/downloads/index.html. ChoosethelatestversionofJavaSE8andinstallit.Ifyoudon’tknowhowtoinstallit, pleasetakealookat http://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html. Testingtheinstallation Onceyouhavecompletedyourinstallation,runthejava-versioncommandfroma commandprompttoverifythatitiscorrectlyinstalled.Hereistheexpectedoutputfroma Windowsmachine: C:\>java–version javaversion“1.8.0_11” Java(TM)SERuntimeEnvironment(build1.8.0_11-b12) JavaHotSpot(TM)64-BitServerVM(build25.11-b03,mixedmode) InstallingWildFly TheJBossWildFlyapplicationservercanbedownloadedforfreefrom http://wildfly.org/downloads/. Asyoucanseeinthefollowingscreenshot,atthemomentofwritingthisbook,thelatest stablereleaseofWildFlyis8.1.0.Final,whichfeaturesaCertifiedJavaEE7fullprofile: Onceyouhavechosentheappropriateserverdistribution,youwillthenbewarnedthat thisdownloadispartofacommunityreleaseand,assuch,isnotsupported. Note IfyouneedEnterprisesupportforyourapplications,youcanoptfortheRedHat EnterpriseApplicationPlatform. Comparedtothecommunityversion,theEAPhasgonethroughdifferentqualitytestsand mightbedifferentintermsoffeatures/packaging.Moreinformationaboutthedifferences betweenEAPandthecommunityversioncanbefoundatthebeginningofthischapter. However,atthetimeofwritingthisbook,EAPdoesnotyetsupportJavaEE7,andno roadmapispubliclyavailable. InstallingWildFlyisapieceofcake;itdoesnotrequireanythingelsebesidesunpacking thewildfly-8.1.0.Final.ziparchive. Windowsuserscansimplyuseanyuncompressingutility,suchasbuilt-incompressed folders(innewerWindowsreleases),WinZip,WinRAR,or7-Ziptakingcaretochoosea foldernamethatdoesnotcontainemptyspacesandwhitespaces.Unix/Linuxshoulduse the$unzipwildfly-8.1.0.Final.zipunzipshellcommandtoexplodethearchive. Note Securitywarning Unix/LinuxusersshouldbeawarethatWildFlydoesnotrequirerootprivileges,asnone ofthedefaultportsusedbyWildFlyarebelowtheprivilegedportrangeof1024.To reducetheriskofusersgainingrootprivilegesthroughWildFly,installandrunWildFlyas anon-rootuser. StartingWildFly AfteryouhaveinstalledWildFly,itiswisetoperformasimplestartuptesttovalidatethat therearenomajorproblemswithyourJavaVM/operatingsystemcombination.Totest yourinstallation,movetothebindirectoryofyourJBOSS_HOME(thepathtowhichyou haveunzippedyourapplicationserver)directoryandissuethefollowingcommand: standalone.bat#Windowsusers $./standalone.sh#Linux/Unixusers ThefollowingisascreenshotofasampleWildFlystart-upconsole: TheprecedingcommandstartsupaWildFlystandaloneinstance,whichisequivalentto startingtheapplicationserverwiththerun.bat/run.shscriptusedbyearlierJBossAS releases.Youwillnoticehowamazinglyfastthenewreleaseoftheapplicationserveris; thisisduetothemodulararchitectureintroducedinVersion7ofJBossAS,whichonly startsupnecessarypartsoftheapplicationservercontainerneededbytheloaded applications. Ifyouneedtocustomizethestart-uppropertiesofyourapplicationserver,openthe standalone.conffile(orstandalone.conf.batforWindowsusers),wherethememory requirementsofWildflyhavebeendeclared.HereistheLinuxcoresectionofthisfile: if[“x$JAVA_OPTS”=“x”];then JAVA_OPTS=”-Xms64m-Xmx512m-XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true” JAVA_OPTS=”$JAVA_OPTS -Djboss.modules.system.pkgs=$JBOSS_MODULES_SYSTEM_PKGS -Djava.awt.headless=true” else echo“JAVA_OPTSalreadysetinenvironment;overridingdefaultsettings withvalues:$JAVA_OPTS” So,bydefault,theapplicationserverstartswithaminimummemoryrequirementof64 MBofheapspaceandamaximumof512MB.Thiswillbejustenoughtogetstarted; however,ifyouneedtorunmorerobustJavaEEapplicationsonit,youwilllikelyrequire atleast1GBofheapspaceor2GBormore,dependingonyourapplicationtype. Generallyspeaking,32-bitmachinescannotexecuteaprocesswhosespaceexceeds2GB; however,on64-bitmachines,thereisessentiallynolimittotheprocesssize. Youcanverifythattheserverisreachablefromthenetworkbysimplypointingyour browsertotheapplicationserver’swelcomepage,whichcanbeaccessedfromthewellknownaddress,http://localhost:8080.ThewelcomepageofWildFlyisshowninthe followingscreenshot: Connectingtotheserverwiththecommand-lineinterface Ifyouhavebeenusingpreviousreleasesoftheapplicationserver,youmighthaveheard aboutthetwiddlecommand-lineutilitythatqueriedMBeansinstalledontheapplication server.Thisutilityhasbeenreplacedbyamoresophisticatedinterfacenamedthe command-lineinterface(CLI);itcanbefoundinJBOSS_HOME/bin. Justlaunchthejboss-cli.batscript(orjboss-cli.shforLinuxusers),andyouwillbe abletomanagetheapplicationserverviaashellinterface.Thisisshowninthefollowing screenshot: Westartedaninteractiveshellsessionthatcanalsousethecommand-linecompletion(by pressingtheTabkey)tomatchpartlytypedcommandnames.Nomoresearchesare neededtofindtheexactsyntaxofcommands! Note Inthepreviousscreenshot,weconnectedtotheserverusingtheconnectcommand;it usestheloopbackserveraddressandplugsintoport9990bydefault. Thecommand-lineinterfaceisdiscussedindepthinChapter9,ManagingtheApplication Server,whichisallaboutservermanagementinterfaces;wewill,however,getaninitial tasteofitsbasicfunctionalitiesinthenextsectionstogetyouaccustomedtothispowerful tool. StoppingWildFly TheeasiestwaytostopWildFlyisbysendinganinterruptsignalwithCtrl+C. However,ifyourWildFlyprocesswaslaunchedinthebackgroundor,rather,isrunningon anothermachine,youcanusetheCLIinterfacetoissueanimmediateshutdown command: [disconnected/]connect Connectedtolocalhost:9990 [standalone@localhost:9990/]:shutdown Locatingtheshutdownscript Thereisactuallyonemoreoptiontoshutdowntheapplicationserverthatisprettyuseful, ifyouneedtoshutdowntheserverfromwithinascript.Thisoptionconsistsofpassing the—connectoptiontotheadminshell,therebyswitchingofftheinteractivemodeas showninthefollowingcommandline: jboss-cli.bat—connectcommand=:shutdown#Windows ./jboss-cli.sh—connectcommand=:shutdown#Unix/Linux StoppingWildFlyonaremotemachine Shuttingdowntheapplicationserverthatisrunningonaremotemachineisjustamatter ofprovidingtheserver’sremoteaddresstotheCLI,andforsecurityreasons,ausername andpassword,asshowninthefollowingcodesnippet(seethenextchaptertolearnmore aboutusercreation): [disconnected/]connect192.168.1.10 Authenticatingagainstsecurityrealm:ManagementRealm Username:admin1234 Password: Connectedto192.168.1.10:9990 [[email protected]:9990/]:shutdown However,youhavetorememberthatyouneedaccesstoagivenportbecauseoften,itmay beblockedbyafirewall. RestartingWildFly Thecommand-lineinterfacecontainsmanyusefulcommands.Oneofthemostinteresting optionsistheabilitytoreloadtheASconfigurationorpartsofitusingthereload command. WhenissuedontherootnodepathoftheASserver,thereloadcommandcanreloadthe services’configuration: [disconnected/]connect Connectedtolocalhost:9990 [standalone@localhost:9990/]:reload InstallingtheEclipseenvironment ThedevelopmentenvironmentusedinthisbookisEclipse,whichisknownbyJava developersworldwide,anditcontainsahugesetofpluginstoexpanditsfunctionalities. Besidesthis,EclipseisthefirstIDEthatiscompatiblewiththenewapplicationserver. So,let’smovetothedownloadpageofEclipse,whichislocatedathttp://www.eclipse.org. Fromhere,downloadthelatestEnterpriseEdition(atthetimeofwritingthisbook,itis Version4.4andisalsoknownasLuna).ThecompressedpackagecontainsalltheJavaEE pluginsalreadyinstalled.Thisisshowninthefollowingscreenshot: Onceyouhaveunzippedthepreviouslydownloadedfile,youwillseeafoldernamed eclipse.Inthisfolder,youwillfindtheEclipseapplication(abigbluedot).Itis recommendedthatyoucreateashortcutonthedesktoptosimplifythelaunchingof Eclipse.Notethat,justaswithWildFly,Eclipsedoesnothaveaninstallationprocess. Onceyouhaveunzippedthefile,youaredone! InstallingJBossTools ThenextstepwillbeinstallingtheJBossASpluginthatisapartofthesuiteofplugins namedJBossTools.InstallingnewpluginsinEclipseisprettysimple;justfollowthese steps: 1. Fromthemenu,navigatetoHelp|InstallNewSoftware. 2. Then,clickontheAddbutton,whereyouwillenterJBossTools’downloadURL (alongwithadescription), http://download.jboss.org/jbosstools/updates/development/luna/.Thisisshowninthe followingscreenshot: 3. Asyoucanseeintheprecedingscreenshot,youneedtochecktheJBossASTools pluginandmoveforwardtothenextoptiontocompletetheinstallationprocess. Note EnterJBossASintothefilterfieldtoquicklyfindtheJBossASToolspluginamong thelargesetofJBossTools. 4. Oncedone,restarttheprocesswhenprompted. Note YoucanalsodownloadJBossToolsasindividualzipfilesforanofflineinstallation. SeeJBossToolsDownloadsathttp://tools.jboss.org/downloads/. 5. Now,youshouldbeabletoseeWildFlylistedasaserverbynavigatingtoNew| ServerfromtheuppermenuandexpandingtheJBossCommunityoption,asshown inthefollowingscreenshot: CompletingtheserverinstallationinEclipseisquitestraightforwardasitjustrequires pointingtothefolderwhereyourserverdistributionis;wewillthereforeleavethistoyou toimplementasapracticalexercise. Alternativedevelopmentenvironments Sincethisbookisallaboutdevelopment,weshouldalsoaccountforsomeother alternativesthatmightsuityourprogrammingstyleoryourcompanystandardsbetter.So, anothervalidalternativeisIntelliJIDEA,whichisavailableat http://www.jetbrains.com/idea/index.html. IntelliJIDEAisacode-centricIDEfocusedondeveloperproductivity.Theeditorexhibits aniceunderstandingofyourcodeandmakesgreatsuggestionsrightwhenyouneedthem andisalwaysreadytohelpyoushapeyourcode. Twoversionsofthisproductexist—CommunityeditionandUltimateedition—that requirealicense.InordertouseJavaEEandtheWildFlyplugin,youneedtodownload theultimateeditionfromhttp://www.jetbrains.com/idea/download/index.htmlandthen simplyinstallitusingtheinstallationwizard. OnceyouhaveinstalledtheUltimateedition,youwillbeabletogetstartedwith developingapplicationswithWildFlybygoingtoFile|SettingsandchoosingtheIDE Settingsoption.Here,youcanchoosetoaddnewapplicationserverenvironments.Thisis showninthefollowingscreenshot: AnotherdevelopmentoptionthatisquitepopularamongdevelopersisNetBeans (http://netbeans.org),whichhassupportforWildFlyinitsreleases7.4and8.0,but requiresinstallationofadditionalpluginsavailableintheNetBeanspluginsregistry. InstallingMaven Besidesgraphicaltools,youarestronglyencouragedtolearnaboutMaven,thepopular buildandreleasemanagementtool.ByusingMaven,youwillenjoythefollowingthings: Astandardstructureforallyourprojects Acentralizedandautomaticmanagementofdependencies Mavenisdistributedinseveralformats,foryourconvenience,andcanbedownloaded fromhttp://maven.apache.org/download.html. Oncethedownloadiscomplete,unzipthedistributionarchive(forexample,apachemaven-3.1.1-bin.zipforWindows)tothedirectoryinwhichyouwishtoinstallMaven 3.1.0(orthelatestavailableversion),forexample,C:\Programs\apache-maven-3.1.1. SomeoperatingsystemssuchasLinuxorOSXofferMavenpackagesintheirapplication repositories. Oncedone,addtheM2_HOMEenvironmentvariabletoyoursystemsothatitwillpointto thefolderwhereMavenhasbeenunpacked. Next,updatethePATHenvironmentvariablebyaddingtheMavenbinariestoyoursystem path.Forexample,ontheWindowsplatform,youshouldinclude%M2_HOME%/bininorder tomakeMavenavailableonthecommandline. SomeadditionalMavenlearningmaterialsareavailableontheSonatypewebsiteinthe formoffreebooks;refertohttp://www.sonatype.com/resources/books. Testingtheinstallation Onceyouhavecompletedyourinstallation,runthemvnversiontoverifythatMavenhas beencorrectlyinstalled.Refertothefollowingcodesnippettoverifythecorrect installation: >mvn–version ApacheMaven3.1.1(0728685237757ffbf44136acec0402957f723d9a;2013-09-17 17:22:22+0200) Mavenhome:C:\Programs\Dev\apache-maven-3.1.1 Javaversion:1.8.0_11,vendor:OracleCorporation Javahome:C:\Programs\Java\jdk1.8.0\jre Defaultlocale:en_US,platformencoding:Cp1250 OSname:“windows8.1”,version:“6.3”,arch:“amd64”,family:“dos” Note Downloadingtheexamplecode YoucandownloadtheexamplecodefilesforallPacktbooksyouhavepurchasedfrom youraccountathttp://www.packtpub.com.Ifyoupurchasedthisbookelsewhere,youcan visithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlyto you. Summary Inthischapter,weranourfirstmileonthetracktoapplicationserverdevelopment.We introducedthenewfeaturesoftheapplicationserverandhadanoverviewoftheJava PlatformEnterpriseEditioninVersion7,alsoknownasJavaEE7. Next,wediscussedtheinstallationoftheWildFlyASandallthecorecomponentsthat includeJDKandasetofdevelopmenttools,suchasEclipseandMaven,whichwillbe yourcompanionsonthisjourney. Inthenextchapter,wewillsummarizealltheapplicationserverfeatureswithaspecial focusonthecomponentsandcommandsneededtodeliveranapplication,whichisthe mainaimofthisbook. Chapter2.YourFirstJavaEEApplicationon WildFly Thischapterwillprovideyouwithacrashcourseinthenewapplicationserversothatyou willbeabletocreateadeployableskeletonofourfirstJavaEE7applicationinthenext chapter.Morespecifically,wewillcoverthefollowingtopics: AnintroductiontotheWildFly8coreconcepts TheanatomyoftheWildFly8filesystem Anintroductiontotheavailablemanagementinstruments DeployingyourfirstHelloWorldapplication WildFly8coreconcepts NowthatwehavedownloadedandinstalledWildFly8,itisworthspendingafewminutes familiarizingourselveswithsomebasicconcepts.Thearchitectureandmostofthecore ideasaretakenstraightfromJBossAS7;although,therearesomenewmechanismsthat wereintroducedwiththenewestversion(forexample,role-basedsecurityforthe managementsystem,reducednumberofusedports,andanewpatchingsystem).Justlike JBossAS7,WildFlycanberunintwomodes:thestandalonemodeanddomainmode. Inthestandalonemode,eachWildFlyinstanceisanindependentprocess(similartothe previousJBossASversions,suchasVersion4,Version5,Version6,andthestandalone modeinVersion7).Thestandaloneconfigurationfilesarelocatedunderthe standalone/configurationdirectoryoftheapplicationserver. Inthedomainmode,youcanrunmultipleapplicationserversandmanagethemfroma centralpoint.Adomaincanspanmultiplephysical(orvirtual)machines.Oneach machine,wecaninstallseveralinstancesofWildFlythatareunderthecontrolofaHost Controllerprocess.Theconfigurationfilesinthedomainmodearelocatedunderthe domain/configurationfolderoftheapplicationserver. Fromtheprocesspointofview,adomainismadeupofthreeelements: DomainController:Thedomaincontrolleristhemanagementcontrolpointofyour domain.AWildFlyinstancerunninginthedomainmodewillhaveatthemostone processinstanceactingasadomaincontroller.Thedomaincontrollerholdsa centralizedconfiguration,whichissharedbythenodeinstancesthatbelongtothat domain. HostController:Thisistheprocessthatisresponsibleforcoordinatingthelifecycle ofserverprocessesandthedistributionofdeploymentsfromthedomaincontrollerto theserverinstances. Applicationservernodes:TheseareregularJavaprocessesthatmapinstancesofthe applicationserver.Eachservernode,inturn,belongstoaservergroup.Domain groupsareexplainedindetailwhenwewilldiscussthedomainconfigurationfile. Additionally,whenstartingadomain,youwillseeanotherJVMprocessrunningonyour machine.ThisistheProcessController.Itisaverylightweightprocesswhoseprimary functionistospawnserverprocessesandHostControllerprocesses,andmanagetheir input/outputstreams.SinceProcessControllerisnotconfigurable,wewillnotdiscussit anyfurther. Thefollowingdiagramdepictsatypicaldomaindeploymentconfiguration: Asyoucanseeintheprecedingdiagram,onehost(Host1)actsasadedicateddomain controller.Thisisacommonpracticeadoptedindomain-managedserversinorderto logicallyandphysicallyseparatetheadministrationunitfromtheserverswherethe applicationsarehosted. Theotherhosts(Host2andHost3)containthedomainapplicationservers,whichare dividedintotwoservergroups:main-server-groupandother-server-group.Aserver groupisalogicalsetofserverinstancesthatwillbemanagedandconfiguredtogether. Eachservergroupcan,inturn,beconfiguredwithdifferentprofilesanddeployments;for example,intheprecedingdomain,youcanprovidesomeserviceswithmain-servergroupandotherserviceswithother-server-group. Thishassomeadvantages.Forexample,whenyoudon’twanttoshutdownyour applicationforanewversion,youcanstartbyredeployingonlyoneservergroupata time.Whenoneserverisnotfullyoperational,requestscanbehandledbythesecondone. Gettingintothedetailsofthedomainconfigurationisbeyondthescopeofthisbook; however,bytheendofthischapter,wewillseehowtodeployapplicationunitsina domainusingthecommand-lineinterfaceavailableinWildFly. TheWildFly8directorylayout Thedifferencebetweenstandaloneanddomainreflectsinthedirectorylayoutofthe applicationserverisshowninthefollowingdiagram: Asyoucanseeintheprecedingdiagram,theWildFlydirectorylayoutisdividedintotwo mainparts:thefirstoneispertinenttoastandaloneservermodeandtheotherisdedicated toadomainservermode.Commontobothservermodesisthemodulesdirectory,which istheheartoftheapplicationserver. WildFlyisbasedontheJBossModulesproject,whichprovidesanimplementationofa modular(nonhierarchical)classloadingandanexecutionenvironmentforJava.Inother words,ratherthanasingleclassloaderthatloadsallJARsintoaflatclasspath,each librarybecomesamodule,whichonlylinkstotheexactmodulesitdependsonand nothingmore.Itimplementsathreadsafe,fast,andhighlyconcurrentdelegatingclass loadermodel,coupledwithanextensiblemoduleresolutionsystem.Thiscombinesto formaunique,simple,andpowerfulsystemforapplicationexecutionanddistribution. Thefollowingtabledetailsthecontentofeachfolderpresentintherootfolderof JBOSS_HOME: Folder Description bin Thisfoldercontainsthestartupscripts,startupconfigurationfiles,andvariouscommand-lineutilities,suchasvault,add-user,andJavadiagnosticreportsavailableforUnixandWindows environments bin/client ThisfoldercontainsaclientJarforusebytheremoteEJBandCLIandclientsnotusinganybuildsystemswithautomaticdependencymanagementsuchasMaven,AntwithIvy,orGradle bin/init.d NewinWildFly,thisfoldercontainsscriptsforRedHatLinuxandDebian,whichregistersWildFlyasaLinuxservice bin/service NewinWildFly,thisfoldercontainsascriptthatallowstoregisterWildFlyasaWindowsservice docs/examples Thisfoldercontainssomesamplestandaloneconfigurationssuchasaminimalstandaloneconfiguration(standalone-minimalistic.xml) docs/schema ThisfoldercontainsXMLschemadefinitionfiles domain Thisfoldercontainstheconfigurationfiles,deploymentcontent,andwritableareasusedbythedomainmodeprocessesrunfromthisinstallation modules Thisfoldercontainsallthemodulesinstalledontheapplicationserver standalone Thisfoldercontainstheconfigurationfiles,deploymentcontent,andwritableareasusedbythesinglestandaloneserversrunfromthisinstallation appclient Thisfoldercontainstheconfigurationfiles,deploymentcontent,andwritableareasusedbytheapplicationclientcontainerrunfromthisinstallation welcomecontent ThisfoldercontainsthedefaultWelcomepagecontent Diggingintothestandalonemodetree,wecanfindfoldersthatarepertinenttostandalone independentprocesses.Ifyouhaveexperiencewithearlierserverreleases,youwillfind thesefoldersquiteintuitivetoyou: Directory Description configuration Thisdirectorycontainstheconfigurationfilesforthestandaloneserverthatrunsfromthisinstallation.Allconfigurationinformationfortherunningserverislocatedhereandisthesingleplacefor configurationmodificationsforthestandaloneserver. data Thisdirectorycontainsthepersistentinformationwrittenbytheservertosurvivearestartoftheserver. deployments Theenduserdeploymentcontentcanbeplacedinthisdirectoryforautomaticdetectionanddeploymentofthatcontentintotheserver’sruntime. lib/ext ThisdirectoryisthelocationfortheinstalledlibraryJarfiles,referencedbytheapplicationsusingtheExtension-Listmechanism. log Thisdirectorycontainsthestandaloneserverlogfiles. tmp Thisdirectorycontainsthelocationofthetemporaryfileswrittenbytheserver. Thedomaindirectorystructureisquitesimilartothestandaloneequivalent,withone importantdifference.Asyoucanseefromthefollowingtable,thedeploymentsfolderis notpresentsincethedomainmodedoesnotsupportdeployingcontentbasedonscanning afilesystem.WeneedtousetheWildFlymanagedinstruments(CLIandwebadmin console)inordertodeployapplicationstoadomain. Directory Description ThisdirectorycontainstheconfigurationfilesforthedomainHostControllerandanyserversrunningonthisinstallation.Alltheconfigurationinformationfortheserversmanagedwithinthedomainis configuration locatedhereandisthesingleplaceforconfigurationinformation. data/content ThisdirectoryisaninternalworkingareafortheHostController,whichcontrolsthisinstallation.Thisiswhereitinternallystoresthedeploymentcontent.Thisdirectoryisnotmeanttobemanipulated bytheendusers.Itiscreatedafterthefirstserverstartup. log ThisdirectoryisthelocationwheretheHostControllerprocesswritesitslogs.TheProcessController,asmall,lightweightprocessthatactuallyspawnsotherHostControllerprocessesandany applicationserverprocesses,alsowriteslogshere.Itiscreatedafterthefirstserverstartup. Thisdirectoryisawritableareausedbyeachapplicationserverinstancethatrunsfromthisinstallation.Eachapplicationserverinstancewillhaveitsownsubdirectory,createdwhentheserverisfirst started.Ineachserver’ssubdirectory,thefollowingsubdirectorieswillbepresent: servers data:Thisistheinformationwrittenbytheserverthatneedstosurvivearestartoftheserver log:Thisistheserver’slogfiles tmp:Thisisthelocationofthetemporaryfileswrittenbytheserver.Thisfolderiscreatedafterthefirstserverstartup. tmp Thisdirectorycontainsthelocationofthetemporaryfileswrittenbytheserver. Managingtheapplicationserver WildFlyprovidesthreedifferentmeanstoconfigureandmanageservers:awebinterface, acommand-lineclient,andasetofXMLconfigurationfiles.Nomatterwhatapproach youchoose,theconfigurationisalwayssynchronizedacrossthedifferentviewsand finallypersistedtotheXMLfiles.Aftersavingthechangesusingthewebinterface,you willinstantlyseeanupdatedXMLfileinyourserver’sconfigurationdirectory. ManagingWildFly8withthewebinterface ThewebinterfaceisaGoogleWebToolkit(GWT)application,whichcanbeusedto manageastandaloneordomainWildFlydistribution.TheGWTapplicationknownin JBossAS7hasbeenupdatedtomatchthenewvisualtheme.Itwasalsoextendedwith newfeatures,suchasrole-basedsecurityandpatchingsupport.Bydefault,itisdeployed onalocalhostonthe9990port;thepropertythatcontrolstheportsocketbindingis jboss.management.http.port,asspecifiedintheserverconfiguration (standalone.xml/domain.xml).Theserverconfigurationisgiveninthefollowingcode snippet: <socket-binding-groupname=“standard-sockets”default-interface=“public”> <socket-bindingname=“management-http”interface=“management” port=”${jboss.management.http.port:9990}”/> ……… </socket-binding-group> Note Wildfly8issecuredoutoftheboxandthedefaultsecuritymechanismisbasedona usernameorpassword,makinguseofHTTPDigest.Thereasonforsecuringtheserverby defaultisthatifthemanagementinterfacesareaccidentallyexposedonapublicIP address,authenticationisrequiredtoconnect.Forthisreason,thereisnodefaultuserin thedistribution. Theusersarestoredinapropertiesfilecalledmgmt-users.propertiesunder standalone/configurationordomain/configurationdependingontherunningmodeofthe server.Thisfilecontainstheusernameinformationalongwithaprecalculatedhashofthe username,plusthenameoftherealmanduser’spassword. Tomanipulatethefilesandaddusers,theserverhasprovidedutilitiessuchasadduser.shandadd-user.battoaddtheusersandgeneratehashes.Sojustexecutethescript andfollowtheguidedprocess.Thisisshowninthefollowingscreenshot: Inordertocreateanewuser,youneedtoprovidethefollowinginformation: Typeofuser:ThetypeofuserwillbeManagementUser,sinceitwillmanagethe applicationserver. Realm:Thismustmatchtherealmnameusedintheconfiguration,sounlessyou havechangedtheconfigurationtouseadifferentrealmname,leavethissetto ManagementRealm. Username:Thisistheusernameoftheuseryouareadding. Password:Thisistheuser’spassword. Usergroups:Thisisalistofcomma-separatedgroupsthatshouldbeassignedtothe newlycreateduser;theyareusedfortherole-basedaccesscontrolandauditing system,whichwasintroducedinWildFly.Theinformationaboutusergroupsis storedinthemgmt-groups.propertiesfile. Ifthevalidationissuccessful,youwillbeaskedtoconfirmwhetheryouwanttoaddthe user;onlythenthepropertiesfileswillbeupdated. Thefinalquestion(IsthisnewusergoingtobeusedtoconnectoneASprocessto another?)canbeusedtoaddtheslaveHostControllersthatauthenticateagainsta masterdomaincontroller.This,inturn,requiresaddingthesecretkeytoyourslavehost’s configurationinordertoauthenticatewiththemasterdomaincontroller.(Formore informationaboutdomainconfiguration,pleasevisit https://docs.jboss.org/author/display/WFLY8/Admin+Guide#AdminGuideManagedDomain.) Launchingthewebconsole Nowthatwehaveaddedatleastoneuser,wecanlaunchthewebconsoleatthedefault address,http://<host>:9990/console(keepinmindthatyouhavetostarttheserver first,forexample,withstandalone.batorstandalone.sh). Theloginscreenwillbeprompted.EnterdataintotheUserNameandPasswordfields, whichwehadformerlycreated.Thisisshowninthefollowingscreenshot: Onceloggedin,youwillberedirectedtothewebadministrationmainscreen.Theweb console,whenrunninginthestandalonemode,willbedividedintothreemaintabs: Configuration,Runtime,andAdministration.Thisisshowninthefollowing screenshot: TheConfigurationtabcontainsallthesinglesubsystemsthatarepartofaserverprofile. So,onceyouselecttheConfigurationtabontheleftframe,youcanaccessallthe subsystemsandedittheirconfigurations(inthepreviousscreenshot,wesawtheData Sourcessubsystem). TheothertabnamedRuntimecanbeusedfortwomainpurposes:tomanagethe deploymentofapplicationsandchecktheservermetrics.Thisisshowninthefollowing screenshot: TheAdministrationtabhasbeenintroducedwithWildFlyandRedHatJBossEAP6.2 andcurrentlycontainsonlytheoptionsassociatedwithrolebasedaccesscontrol.Youcan nowlimitpermissionsofmanagementusers,forexample,sothatnoteveryadministrator canundeployanapplicationusingthewebconsole.Bydefault,thisfeatureisdisabled. YouhavetoenableitmanuallyusingtheCLImechanism.Thisisshowninthefollowing screenshot: Onceyouhavelearnedhowtoaccessthewebconsole,itisabouttimeyoutryyourfirst applicationexample. DeployingyourfirstapplicationtoWildFly8 Inordertotestlaunchourfirstapplication,wewillcreateaHelloWorldwebprojectusing Eclipse.Themainpartwillbeaservletclass,usedtogenerateHTMLmarkup.So, launchEclipseandchoosetocreateanewwebprojectbynavigatingtoFile|New| DynamicWebProject.Thisisshowninthefollowingscreenshot: ChooseanameforyourapplicationandchecktheUsedefaultlocationboxifyouwantto createyourprojectwithinthesamelocationofyourEclipseworkspace.Ifyouhave correctlyconfiguredanewWildFlyserverinEclipse,youshouldseetheWildFly8.0 Runtimeoptionselectedbydefault,andTargetRuntimeandDefaultConfigurationfor WildFly8.0RuntimepreselectedintheConfigurationbox. Select3.1astheDynamicwebmoduleversion,whichmakesdevelopmenteasybyusing theServlet3.1specifications,andalsoleavetheEARmembershipandAddprojectto workingsetscheckboxesunselected. ClickonFinishtocontinue. Now,let’saddaquintessentialsimpleservlettoourproject,whichmerelydumpsaHello WorldmessageasanHTMLpage.FromtheFilemenu,gotoNew|Servletandentera meaningfulnameandpackageforyourservlet,suchasTestServletasthenameand com.packtpub.wflydevelopment.chapter2asthepackagename.Thisisshowninthe followingscreenshot: Thewizardwillgenerateabasicservletskeletonthatneedstobeenhancedwiththe followingsetofcodelines: @WebServlet(“/test”) publicclassTestServletextendsHttpServlet{ privatestaticfinallongserialVersionUID=1L; privatestaticfinalStringCONTENT_TYPE= “text/html;charset=UTF-8”; privatestaticfinalStringMESSAGE=“<!DOCTYPEhtml><html>”+ “<head><title>Hello!</title></head>”+ “<body>HelloWorldWildFly</body>”+ “</html>”; @Override protectedvoiddoGet(HttpServletRequestrequest, HttpServletResponseresponse) throwsServletException,IOException{ response.setContentType(CONTENT_TYPE); try(PrintWriterout=response.getWriter()){ out.println(MESSAGE); } } } TheservletwillrespondwithastaticHTMLpage(wedefinedthecontenttypeas Text/HTMLwithanUTF-8charset)foreveryGETHTTPrequestthatwillbeissued againstitsURLaddress. Note NoticethatTextServletbearsthe@WebServletannotation,whichhasbeenintroducedby theServlet3.0API,anditallowsregisteringaservletwithoutusingtheweb.xml configurationfile.Inourexample,weusedittocustomizetheservletURLbindingto employ/test,whichwouldotherwisebedefaultedbyEclipsetotheclassname. WewillcompletetheapplicationwiththecreationofaJBossfiledescriptornamed jboss-web.xmlin/WebContent/WEB-INF/directory;althoughthisisnotmandatory,it canbeusedtoredefinethecontextroot,asshowninthefollowingcodesnippet: <jboss-web> <context-root>/hello</context-root> </jboss-web> Note Theschemadefinitionfileforjboss-web.xmlisnamedjboss-web_8_0.xsdandcanbe locatedintheJBOSS_HOME/docs/schemafolder. Keepinmindthatcreatingjboss-web.xmlmakestheapplicationnon-portabletoother JavaEEApplicationServers.Thedefaultapplicationpathwhensuchafileisnotdefined isaconcatenationoftheapplicationnameanditsversion,forexample,forapplication TestServletwithVersion1.0,itwouldbeTestServlet-1.0. Now,wewilladdthewebapplicationtothelistofdeployedresourcesbyright-clickingon theEclipseServertabandselectingAddandRemove.Thisisshowninthefollowing screenshot: Next,clickonAddtoaddtheprojecttothelistofconfiguredresourcesontheserveras showninthefollowingscreenshot: IfyouhavestartedWildFlyfrominsideEclipse,theresourcewillbeautomatically deployedbycheckingtheflagtoseewhethertheserverhasstarted,andpublishchanges immediately. If,ontheotherhand,youhavestartedtheapplicationserverexternally,thenyoucanfully publishyourresourcebyright-clickingontheapplicationandselectingFullPublishas showninthefollowingscreenshot: Now,movetothebrowserandcheckthattheapplicationrespondsattheconfiguredURL, asshowninthefollowingscreenshot: ThisexampleisalsoavailableintheformofaMaven(willbeintroducedinthenext chapter)projectinyourPacktPublishingaccount. AdvancedEclipsedeploymentoptions Asitis,EclipsehaspublishedaHelloWorld.warfolderin JBOSS_HOME/standalone/deployments. Note YoumighthavenoticedthatEclipsehasalsoaddedamarkerfilenamed HelloWorld.war.dodeploy.Thisstepisnecessarybecause,bydefault,exploded deploymentsinWildFlyaren’tautomaticallydeployed.Autodeploymentoftheexploded contentisdisabledbydefaultbecausethedeploymentscannercouldtrytodeploythe copieddirectorypartially,whichwouldcausealotoferrors.Thedeploymentofthe explodedarchivescanbemanuallytriggeredwithamarkerfilenamedapplication. [jar/war/ear].dodeploy. Oncetheapplicationisdeployed,theapplicationserverreplacesthe.dodeploymarker filewithHelloWorld.wardeployed,orwithaHelloWorld.war.failedfile,shouldthe deploymentfail. Youcanchangethedefaultdeploymentoptionsbydouble-clickingonWildFly8.0(inthe Servertab),andselectingtheDeploymenttabasshowninthefollowingscreenshot: IntheDeploymenttab,youcanchoosetodeployyourapplicationonacustomdeploy folderbycheckingtheUseacustomdeployfolderoptionandenteringanappropriate valueintothecorrespondingtextbox. PleasenotethatthecustomdeploymentfolderalsoneedstobedefinedinWildFly;check thenextsectionformoreinformationaboutit. Also,takenoteoftheDeployprojectsascompressedarchivesoption,whichcanbe usefulinsomecircumstances,forexample,ifyouaredistributingtheapplicationviaother instrumentssuchastheCLI,whichcandeployonlycompressedarchives. Managingdeploymentswiththewebconsole DeployingtheapplicationusingEclipseisastraightforwardtaskandislikelytobeyour optionwhenyouaredevelopingapps.Wewillseeherehowtousethewebconsoleto deploytheapplication,whichcanbeonemorearrowinyourquiver. Note AtypicalscenarioforthisexamplecouldbeifyouarerunningtheASinthedomain mode,orsimplydeployingyourapplicationonaremoteWildFlyinstance. StartthewebconsoleandclickontheRuntimetab.Fromthepanelontheleft,goto Server|ManageDeploymentsasshowninthefollowingscreenshot: Inthecentralpanel,wecanmanagedeploymentsusingtheAdd,Remove,En/Disable, andUpdatebuttons.SelecttheAddbuttontoaddanewdeploymentunit.Inthenext screen,pickupthefileyouwanttodeploy(forexample,theHelloWorld.warartifact, whichcanbecreatedfromourtestprojectinEclipsebynavigatingtoFile|Export|Web |WARFile)fromyourlocalfilesystem,asshowninthefollowingscreenshot: Completethewizardbyverifyingthedeployment’snameandclickingonSave,asshown inthefollowingscreenshot: Now,thedeploymentislistedintheDeploymentstable.Itis,however,notenabledby default.ClickontheEn/Disablebuttontoenablethedeploymentoftheapplication,as showninthefollowingscreenshot: Changingthedeploymentscannerproperties Aswehaveseenbefore,applicationsrunninginthestandalonemodearescannedinthe deploymentsfolderbydefault.Youcanchangethisbehavior(andalsothedeployment scanner’sproperties)byclickingontheConfigurationtabandnavigatingtoSubsystems |Core|DeploymentScannersfromtheleftmenu.Thisisshowninthefollowing screenshot: InDeploymentScanners,youcansetthecoredeployment’sattributes.Youcanclickon theEditbuttontodefinenewvaluesfortheseproperties.Mostofthemareselfexplanatory;however,thefollowingtablesummarizesthem: Attribute Description name Thisisthedeploymentscanner’sname(bydefault,thenamedefaultisprovided). path Thisistheabsolutepathwheredeploymentsarescanned.IftheattributePathRelativetoisset,thenit’sappendedtotherelativepathdefinition. Enabled Thisattributedetermineswhetherthedeploymentscannerisenabledornot. PathRelativeto Ifincluded,thisattributemustpointtoasystempaththatwillbeusedtobuildtherelativepathexpression. ScanInterval Thisisthetimefrequency(inmilliseconds)forwhichdeploymentswillbescanned. Auto-deployZipped Settingthistotruewillenableautomaticdeploymentsforzippedapplications.Itsdefaultvalueistrue. Auto-deployExploded Settingthistotruewillenableautomaticdeploymentsforexplodedapplications.Itsdefaultvalueistrue. Deploymenttimeout Thisreferstothetime-outafterwhichadeploymentactionwillbemarkedasfailed. Deployingapplicationsusingthecommand-lineinterface AnotherwaytodeployanapplicationisviatheWildFlyCommand-lineInterface(CLI), whichcanbestartedfromjboss-cli.bat(orjboss-cli.shforLinuxusers).Don’tbe afraidofusingatextualinterfacetomanageyourapplicationserver;asamatteroffact, theconsoleprovidesbuilt-inautocompletefeaturesandyoucandisplaytheavailable commandsatanytimebysimplyhittingtheTabkey,asshowninthefollowing screenshot: Asyoumighthaveguessed,inordertodeployanapplication,youneedtoissuethe deployshellcommand.Whenusedwithoutarguments,thedeployshellcommand providesalistofapplicationsthatarecurrentlydeployed.Refertothefollowingcode: [standalone@localhost:9990/]deploy ExampleApp.war Ifyoufeedaresourcearchivesuchas.wartoshell,itwilldeployitonthestandalone serverrightaway,asshowninthefollowingcommandline: [standalone@localhost:9990/]deploy../HelloWorld.war Asyoucanseefromtheprecedingcommandline,theCLIusesthefolderwhereyour deploymentswereactuallylaunchedatitsinitiallocation,whichisJBOSS_HOME/binby default.Youcan,however,useabsolutepathswhenspecifyingthelocationofyour archives;theCLIexpansionfacility(usingtheTabkey)makesthisoptionfairlysimple. Thisisdemonstratedinthefollowingcommandline: [standalone@localhost:9990/]deployc:\deployments\HelloWorld.war Thereisnoerrormessageafterissuingthecommand;therefore,theapplicationis deployedandactivatedsothattheusercanaccessit.Ifyouwanttojustperformthe deploymentoftheapplicationanddefertheactivationtoalatertime,youhavetoaddthe —disabledswitch,asshowninthefollowingcommandline: [standalone@localhost:9990/]deploy../HelloWorld.war—disabled Inordertoactivatetheapplication,simplyissueanotherdeployshellcommandwithout the—disabledswitch,asshowninthefollowingcommandline: [standalone@localhost:9990/]deploy-–name=HelloWorld.war Redeployingtheapplicationrequiresanadditionalflagforthedeployshellcommand. Usethe-fargumenttoforcetheapplication’sredeployment,asshowninthefollowing commandline: [localhost:9990/]deploy-f../HelloWorld.war Undeployingtheapplicationcanbedonewiththeundeploycommand,whichtakesthe applicationthatisdeployedasanargument.Thisisshowninthefollowingcommandline: [localhost:9990/]undeployHelloWorld.war Deployingapplicationstoadomain Deployingapplicationswhenrunninginthedomainmodeisslightlydifferentfromdoing thisinthestandalonemode.Thedifferenceboilsdowntothefactthatanapplicationcan bedeployedjusttooneservergrouportoalltheservergroups.Asamatteroffact,one reasonwhyyoumightsplityourdomainintodifferentservergroupsmightbethatyouare planningtoofferdifferenttypesofservices(andhenceapplications)toeachservergroup. So,inordertodeployyourHelloWorld.warapplicationtoallservergroups,issuethe followingcommand: [domain@localhost:9990/]deployHelloWorld.war—all-server-groups If,ontheotherhand,youwanttoundeployanapplicationfromallservergroups belongingtoadomain,youhavetoissuetheundeploycommand,asshowninthe followingcommandline: [domain@localhost:9990/]undeployHelloWorld.war—all-relevant-servergroups Youcanalsodeployyourapplicationjusttooneservergroupofyourdomainby specifyingoneormoreservergroups(separatedbyacomma)withthe—server-groups parameter,asshowninthefollowingcommandline: [domain@localhost:9990/]deployHelloWorld.war—server-groups=main-servergroup Youcanusethetabcompletionfacilityinordertocompletethevalueforthelistof— servergroupselectedfordeployment. Now,supposewewishtoundeploytheapplicationfromjustoneservergroup.Therecan betwopossiblescenarios.Iftheapplicationisavailablejustonthatservergroup,youwill justneedtofeedtheservergrouptothe—server-groupsflag,asshowninthefollowing commandline: [domain@localhost:9990/]undeployHelloWorld.war—server-groups=main- server-group Ontheotherhand,ifyourapplicationisavailableonotherservergroupsaswell,youneed toprovidetheadditional—keep-contentflag;otherwise,theCLIwillcomplainthatit cannotdeleteanapplicationthatisreferencedbyotherservergroups,asshowninthe followingcommandline: [domain@localhost:9990/]undeployHelloWorld.war—server-groups=mainserver-group—keep-content Summary Inthischapter,wewentthroughacrashcourseontheapplicationserver,focusingonthe availablemanagementinstruments:thewebinterfaceandCommand-lineinterface.We thensawhowtousethesetoolstodeployasampleapplicationtoastandalone environmentanddomainenvironment. Inthenextchapter,wewilldivedeepintoJavaEE7components,startingfromEnterprise JavaBeans,whichstillplaysanimportantroleintheevolvingscenarioofJavaEnterprise applications. Chapter3.IntroducingJavaEE7–EJBs Inthepreviouschapter,youlearnedsomebasicsabouthowtosetupanddeployaHello WorldapplicationonWildFly.Inthischapter,wewillgoalittledeeperandlearnhowto create,deploy,andassembleEnterpriseJavaBeans,whichareattheheartofmost Enterpriseapplications.Additionally,youwilllearnhowtouseMaven,apopularbuild tool,whichcaneasethepackagingprocessofourbeans. Inmoredetail,hereiswhatyouwilllearninthischapter: WhatchangesareintroducedbythenewEJB3.2specification HowtocreateaJavaEE7Mavenproject HowtodevelopasingletonEJB HowtocreatestatelessandstatefulEnterpriseJavaBeans Howtoaddandmanageschedulersandtimerstoyourapplication HowtomakeuseofasynchronousAPIsinanEJBproject EJB3.2–anoverview BasedontheEnterpriseJavaBeans(EJB)specification,EnterpriseJavaBeansare componentsthattypicallyimplementthebusinesslogicofJavaEnterpriseEdition applications(forJavaEE,notethatOracleadvisesagainstusingJEEastheacronymfor JavaEnterpriseEdition;formoreinformationaboutacronymsforJava-related technologies,visithttps://java.net/projects/javaee-spec/pages/JEE).Becauseoftheir transactionalnature,EJBsarealsocommonlyusedfortheconstructionofthedataaccess layerinmanyapplications.However,inthenewestversionofthespecification,containermanagedtransactionsarenolongerexclusiveforEnterpriseJavaBeansandcanbereused inotherpartsoftheJavaEEplatform. TherearebasicallythreetypesofEnterpriseJavaBeans: Sessionbeans:ThisisthemostcommonlyusedEJBtype.Thecontainermanages multipleinstancesofeveryclassthatisdefinedasasessionbean(withanexception forsingletons,whichhaveonlyoneinstance).Whenanoperationimplementedby EJBmustbeexecuted(forexample,becauseauserhasrequestedanupdateofan entityinthedatabase),thecontainerassignsasessionbeaninstanceforthespecific user.Thiscodeisthenexecutedonbehalfofthecallingclient.Thecontaineris responsibleforprovidingsessionbeanswithmultiplesystem-levelservices,for example,security,transactions,ordistributionofbeans. Message-drivenbeans(MDB):MDBsareEnterprisebeansthatcanasynchronously processmessagessentbyanyJMSproducer.(WewilldiscussMDBsinChapter6, DevelopingApplicationswithJBossJMSProvider.) Entityobjects:AnEJBisusedtorepresententitiesinadatabase.Thenewestversion ofthespecificationmadethistypeofEnterpriseJavaBeansoptional,sotheymaynot besupportedinallcontainers(theirsupporthasalsobeendroppedinWildFly). EntityobjectswillberemovedfromthespecificationinJavaEE8.Currently,inJava EE7,themainpersistencetechnologyisJavaPersistenceAPI.WewilldiscussJPA inChapter5,CombiningPersistencewithCDI. Additionally,sessionbeanscanbedividedintothreesubtypesbasedontheir characteristicsandusagescenarios. Statelesssessionbeans(SLSB):Theseareobjectswhoseinstanceshaveno conversationalstatewiththeclientthathasinvokedanoperationonthem.This meansthatallthesebeaninstancesareequalwhentheyarenotservicingaclient,and thecontainercanprepareapoolforthemtohandlemultiplerequestsinparallel. Becausetheydonotstoreanystate,theirperformanceoverheadisquitelow.A commonusagescenarioforanSLSBwouldbeastatelessserviceresponsiblefor retrievingobjectsfromadatabase. Statefulsessionbeans(SFSB):SFSBsupportsconversationalserviceswithtightly coupledclients.Astatefulsessionbeanaccomplishesataskforaparticularclientand itcannotbesharedbetweenmultiplecallers.Itmaintainsthestateforthedurationof aclientsession.Aftersessioncompletion,thestateisnotretained.Thecontainermay decidetopassivate(serializeandstoreforfutureusage)astaleSFSB.Thisisdoneto saveresourcesoftheapplicationserverorinsomecases,tosupportSFSBfailover mechanisminadomainofapplicationservers(thisisthecaseinJBossAS7and WildFly).StartingfromEJB3.2,itispossibletodisablepassivationforaspecific SFSB,althoughitmayaffecttheserver’sstabilityandfailovercapability.Ashopping cartcouldserveasasimpleusecaseforanSFSB. SingletonEJB:Thisisessentiallysimilartoastatelesssessionbean;however,ituses asingleinstancetoserveclientrequests.So,youcanguaranteetheuseofthesame instanceacrossinvocations.Singletonscanusearicherlifecycleforasetofevents, alongwiththepossibilitytocontrolwhenabeanisinitialized.Also,amorestrict lockingpolicytocontrolconcurrentaccesstotheinstancecanbeenforced,sothat thesharedstateofthesingletonbeancanbeusedbymultipleclients.Ifthe applicationisdistributedonmultiplenodesofadomain,theneveryrunningJVM willhaveitsowninstanceofthesingletonbean.Wewilldiscussthisalittlefurtherin Chapter11,ClusteringWildFlyApplications.Becauseoftheirspecialcharacteristics, singletonscanbeusedtosavethestateoftheapplication,cache,orinitializesome resourcesduringtheapplication’sstartup. Aswementionedearlier,thecontainermanagestheinstancesofthebeans,buttheclients shouldcallthemthroughbusinessinterfaces.Therearethreetypesofasessionbean’s viewsavailable: Localbusinessinterface:Thissessionbeanisusedwhenthebeananditsclientare inthesamecontainer.Itusesthepass-by-referencesemantic,sothereturnvaluesand methodparametersarebasedonreferencesandnotcopiesoftheobjects. Remotebusinessinterface:Inthissessionbean,thelocationsoftheclientandthe beanareindependent(theclientmayresideinanothercontainerorwithouta containeratall,forexample,asastandaloneapplication).Everyparameterandreturn valueisserializedandcopied. No-interfaceview:Thissessionbeanisavariantofthelocalbusinessviewthatdoes notrequireaseparateinterface,thatis,allpublicmethodsofthebeanclassare automaticallyexposedtothecaller. SinceEJB3.1,itispossibletouseasynchronousmethods.Theseareabletoprocessclient requestsasynchronously,justlikeMDBs,exceptthattheyexposeatypedinterfaceand followamorecomplexapproachtoprocessclientrequests.Itispossibletousetwo approachestoachievethiskindofbehavior: Fire-and-forgetasynchronousvoidmethods,whichareinvokedbytheclient Retrieve-result-laterasynchronousmethods,whichhavetheFuture<?>returntype WhatmoreshouldyouknowaboutEJBsbeforeproceeding?Whenyoudevelopan EnterpriseJavaBean,youhavetofollowsomegeneralrules,whichareasfollows: Avoidusingnonfinalstaticfields Don’tmanuallycreatethreads(wewillcoverthistopicmoredeeplyinChapter12, Long-termTasks’Execution) Don’tusesynchronizationprimitives(exceptinsingletonswithbean-managed concurrency) Manualfileoperationsonthefilesystemandlisteningonsocketsareforbidden Nativelibrariesshouldnotbeloaded DisobeyingtheserulescouldcausesecurityandstabilityissueswiththeEJBcontainer.A comprehensivelistofdisallowedactivitiescanbefoundat http://www.oracle.com/technetwork/java/restrictions-142267.htmlalongwithsome explanationsforspecificpoints. Sinceit’seasiertograsptheconceptswithrealexamples,inthenextsection,wewill provideaconcreteapplicationexamplethatintroducessomeofthefeaturesthatwe describedinthissection. DevelopingsingletonEJBs Asthenameimplies,javax.ejb.Singletonisasessionbeanthatguaranteesthatthereis atmostoneinstanceintheapplication. Note Besidesthis,singletonEJBsfillawell-knowngapinEJBapplications,thatis,theability tohaveanEJBnotifiedwhentheapplicationstartsandalsowhentheapplicationstops. So,youcandoallsortsofthingswithanEJBthatyoupreviously(beforeEJB3.1)could onlydowithaload-on-startupservlet.EJBalsogivesyouaplacetoholddatathatpertains totheentireapplicationandalltheusersusingit,withouttheneedforstaticclassfields. InordertoturnyourEJBintoasingleton,allthatisneededistoapplythe @javax.ejb.Singletonannotationontopofit. Note Asingletonbeanissimilartoastatefulbean,inthat,stateinformationismaintained acrossmethodinvocations.However,thereisjustonesingletonbeanforeachserverJVM, anditissharedbyalloftheEJBsandclientsofanapplication.Thistypeofbeanprovides aconvenientmeanstomaintaintheoverallstateofanapplication.However,ifthe applicationisdistributedonmultiplemachines(andthereforemultipleJVMs),the singletonisuniqueoneveryoneofthem.Anyapplicationstatemustbesynchronized betweenthenodes. [email protected],whichcausesthebean tobeinstantiatedbythecontainerwhentheapplicationstarts.Thisinvokesthemethod decoratedwiththe@javax.annotation.PostConstructannotationifyouhavedefined oneinyourEJB. WenowhaveenoughinformationtounderstandourfirstEJBexample.Thereismorethan onealternativetocreateaJavaEnterpriseproject.Intheearlierchapter,weillustratedhow tostartfromaprojectbasedonEclipseJavaEE(adynamicwebproject),bindingitlater toaWildFlyruntimeinstallation.Thisisobviouslythesimplestchoice,andyoucaneasily runtheexamplescontainedinthisbookusingthispattern;however,whenitcomesto enterprisesolutions,it’snosurprisethatalmosteveryprojectnowusessomekindofbuild automationtool.Forthisbook,wewillproposeApacheMaven,asitisoneofthemost popularchoices,butnottheonlyone.GradleisasimilarprojectthatusestheGroovy languagetodescribeprojectstructure,dependencies,andbuildworkflow. SomeofthebenefitsthatyouwillachievewhenturningtoMavenprojectsincludeawelldefineddependencystructure,theconventionsofaprojectbuild’sbestpractices,and projectmodulardesign,justtomentionafew.Additionally,whenyouhaveanautomated buildprocess,youcanusecontinuousintegrationtools(suchasJenkins)toschedule automatedtestsanddeploymentsofyourapplications. AllmajorIDEshavebuilt-inMavensupport.ThisincludestheEclipseJavaEELuna release. So,let’screateourfirstMavenprojectdirectlyfromEclipse.NavigatetoFile|New| Other|Maven|MavenProject.Thisisshowninthefollowingscreenshot: ClickonNext;youwillbetakentothefollowingintermediaryscreen: Mavenallowstheuseofarchetypeswhencreatinganewproject.Theydefineaproject’s basicdependencies,resources,structure,andsoon.Forexample,youcanuseaweb applicationarchetypeinordertogetanemptyprojectskeleton,whichyoucanjustbuild anddeploy.Unfortunately,archetypesareoftenoutdated,andyoustillneedtoadjustthem foryourneeds.InordertousesomeJavaEE7archetypes,youhavetofirstdefinea repositoryandarchetypesyouwouldliketouse,andthenyoucancreateaproject.Inreal life,youwillprobablycreateeverynewprojectbyjustlookingatyourpreviousones, withoutusinganyarchetypes.So,herewewillshowhowtocreateaprojectfromscratch. YoumightalsobeinterestedinsomeadditionalJavaEE-relatedtoolssuchasJBossForge, whosedescriptionyouwillfindintheAppendix,RapidDevelopmentUsingJBossForge. Onthevisiblescreen,checktheCreateasimpleprojectcheckbox.Withthisoption,we willskipthearchetypeselection.YoucanclickonNext.Now,youhavetocompletesome basicprojectinformation.Wearecreatingaserver-sideEJBapplication,whichalsohasa standaloneclient.Thesetwoprojectscansharesomecommoninformation,forexample, aboutdependenciesandtheirversions.Hence,wewanttocreateaMavenmultimodule project.Inthisfirststep,let’screateaparentprojectthathasaPOMpackaging.POMisa Mavenconventionusedtodescribethestructureofaprojectanditsmodules.More informationonthiscanbefoundinSonatypefreebooksthatwementionedinprevious chapters. Youcancompletethewizardbyenteringsomepackage-specificinformation,asshownin thefollowingscreenshot: ForGroupID(anabstractidentifierwithasimilarroleasinJavapackages),youcanuse com.packtpub.wflydevelopment.chapter3.ForArtifactID(asimplifiednameofour project),justuseticket-agency.SetthePackagingfieldtopom,andyoucanleavethe defaultselectionfortheproject’sVersionfield.ClickonFinishinordertocompletethe wizard. Takealookatournewlycreatedproject.Atthemoment,itcontainsonlypom.xml,which willbethebasefornewmodules.NavigateagaintoFile|New|Other|Mavenbutnow choosetheNewMavenModule.Youcannowseethefollowingscreenshot: Again,wewanttoskipthearchetypeselection,sochecktheCreateasimpleproject option.UndertheParentProject,clickonBrowseandselecttheparentwecreateda whileago.UnderModuleName,enterticket-agency-ejb.ClickonNext.Youwillbe presentedwiththefollowingscreen. Now,let’sdiscussthepackagingtype.ThereareafewpossiblearchivetypesforJavaEE deployments: TheEJBmodule:ThismoduleusuallycontainsclassesforEJBs,packedasa.jar file. Thewebmodule:Thisarchivecanadditionallycontainwebelementssuchas servlets,staticwebfiles,RESTendpoints,andsoon.Itispackedasa.warfile(web archive)file. Theresourceadaptermodule:ThisarchivecontainsfilesrelatedtoJCAconnectors (describedinChapter6,DevelopingApplicationswithJBossJMSProvider).Itis packedasa.rarfile. TheEnterprisearchive:ThisarchiveaggregatesmultipleJavaEEmodules(EJB, Web)withrelateddescriptors.Itispackedasa.earfile. Here,wewanttodeployonlyEJBswithoutanywebelements,solet’ssetthepackaging toEJB(ifitisnotvisibleintheEclipsedrop-downmenu,justmanuallytypeit)andclick onFinish. Followthesamestepstoaddasecondmodulewiththenameticket-agency-ejb-client andJARpackaging.Thiswillbeasimpleclientforservicesexposedinticket-agencyejb. Now,lookatourparentprojectpom.xml.Itshoulddefinetworecentlycreatedmodules, whichareasfollows: <modules> <module>ticket-agency-ejb</module> <module>ticket-agency-ejb-client</module> </modules> Theexpectedoutcomeoftheseoperationsshouldmatchthefollowingscreenshot,which hasbeentakenfromtheProjectExplorerview: Asyoucansee,theticket-agency-ejbandticket-agency-ejb-clientprojectshavebeen organizedasastandardMavenproject: src/main/javawillcontainoursourcecode src/main/resourcesismeantfortheconfiguration(containingabare-bonesejbjar.xmlconfigurationfilefortheEJBproject) src/test/javaisusedtostorethetestclasses Atthemoment,wewillfocusonthemainfilepom.xml,whichneedstobeawareofthe JavaEEdependencies. ConfiguringtheEJBprojectobjectmodule(pom.xml) Beforediggingintothecode,firstyouneedtoconfigureMaven’spom.xmlconfiguration filefurther.Thisfileisquiteverbose,sowewillillustratejustthecoreelementsherethat arerequiredtounderstandourexample,leavingthefulllistingtothecodeexample packageofthisbook. ThefirstthingwearegoingtoaddjustafterthepropertiessectionisareferencetoJava EE7API,whichisasfollows: <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> </dependencies> ThisdependencywilladdallJavaEE7.0APIs’definitions.Scopeissettobeprovided, whichmeansthedependencyisavailableonthetargetenvironment(inourcase,the applicationserver),anddoesnotneedtobeincludedinthebuiltarchive.Thisdependency isuniversal,andshouldworkwithallApplicationServersthatarecompatiblewithJava EE7.0,notonlywithWildFly. Wealsowanttoaddaseconddependency,whichistheJBossloggingAPI.Placethis definitioninthesame<dependencies></dependencies>tags,forexample,below javaee-api,asfollows: <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.1.4.GA</version> <scope>provided</scope> </dependency> Note Thescopeprovidedincludestheenterprisedependenciesandcorrespondstoaddinga librarytothecompilationpath.Therefore,itexpectstheJDKoracontainertoprovidethe dependencyatruntime.Besidesdependencies,wewouldliketoconfigurethebuild process.ThecreatedprojectspecifiestheEJBpackaging,butthebuildisperformedwith theJDK1.5compliancelevelandanoldEJBversion.Thisiswhywewanttoaddan additionalblocktopom.xml,whichisasfollows: <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <!—enforceJava8—> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ejb-plugin</artifactId> <version>2.3</version> <configuration> <ejbVersion>3.2</ejbVersion> <!—Generateejb-clientforclientproject—> <generateClient>true</generateClient> </configuration> </plugin> </plugins> </build> Thisblockdoestwothings,whichareasfollows: Themaven-compiler-pluginconfigurationenforcestheusageofJava8 Themaven-ejb-pluginconfigurationdefinesthatEJB3.2versionwasused,and enablesgenerationoftheEJBclient(disabledbydefault)packageforEJBclient applications Also,checkthesrc/main/resources/META-INF/ejb-jar.xmlfile.Itmightcontainthe configurationfromEJB2.1.Instead,usethefollowingcode: <?xmlversion=“1.0”encoding=“UTF-8”?> <ejb-jarxmlns=“http://xmlns.jcp.org/xml/ns/javaee” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/javaee” version=“3.2”> <display-name>ticket-agency-ejb</display-name> <ejb-client-jar>ticket-agency-ejbClient.jar</ejb-client-jar> </ejb-jar> Atthispoint,youwillbeabletocompileyourproject;so,wewillstartaddingclasses,but wewillreturntothepom.xmlfilewhenit’stimetodeployyourartifact. CodingourEJBapplication CreatingEJBclassesdoesnotrequiregettingmixedupwithfancywizards;allyouneed todoisaddbareJavaclasses.Therefore,fromtheFilemenu,gotoNew|JavaClass,and enterTheatreBoxastheclassnameand com.packtpub.wflydevelopment.chapter3.controlasthepackagename. Wewilladdthefollowingimplementationtotheclass: @Singleton @Startup @AccessTimeout(value=5,unit=TimeUnit.MINUTES) publicclassTheatreBox{ privatestaticfinalLoggerlogger= Logger.getLogger(TheatreBox.class); privateMap<Integer,Seat>seats; @PostConstruct publicvoidsetupTheatre(){ seats=newHashMap<>(); intid=0; for(inti=0;i<5;i++){ addSeat(newSeat(++id,“Stalls”,40)); addSeat(newSeat(++id,“Circle”,20)); addSeat(newSeat(++id,“Balcony”,10)); } logger.info(“SeatMapconstructed.”); } privatevoidaddSeat(Seatseat){ seats.put(seat.getId(),seat); } @Lock(READ) publicCollection<Seat>getSeats(){ returnCollections.unmodifiableCollection(seats.values()); } @Lock(READ) publicintgetSeatPrice(intseatId)throwsNoSuchSeatException{ returngetSeat(seatId).getPrice(); } @Lock(WRITE) publicvoidbuyTicket(intseatId)throwsSeatBookedException, NoSuchSeatException{ finalSeatseat=getSeat(seatId); if(seat.isBooked()){ thrownewSeatBookedException(“Seat”+seatId+”already booked!”); } addSeat(seat.getBookedSeat()); } @Lock(READ) privateSeatgetSeat(intseatId)throwsNoSuchSeatException{ finalSeatseat=seats.get(seatId); if(seat==null){ thrownewNoSuchSeatException(“Seat”+seatId+”doesnot exist!”); } returnseat; } } Let’sseeourapplicationcodeindetail;thevoidmethodsetupTheatreisinvokedassoon astheapplicationisdeployedandtakescareofassemblingthetheatreseats,creatinga simplemapoftheSeatobjects.Seatidentifiersarekeyfactorsinthismap.Thishappens rightafterdeploymentbecauseourbeanisannotatedwith@Singletonand@Startupthat forcethecontainertoinitializethebeanduringstartup.EachSeatobjectisconstructed usingasetofthreefieldconstructors,whichincludestheseatID,itsdescription,andthe price(thebookedfieldisinitiallysetasfalse).Thisisgiveninthefollowingcode: publicclassSeat{ publicSeat(intid,Stringname,intprice){ this(id,name,price,false); } privateSeat(intid,Stringname,intprice,booleanbooked){ this.id=id; this.name=name; this.price=price; this.booked=booked; } publicSeatgetBookedSeat(){ returnnewSeat(getId(),getName(),getPrice(),true); } //OtherConstructors,FieldsandGettersomittedforbrevity } NotethatourSeatobjectisanimmutableone.Afterwecreateaninstance,wewillnotbe abletochangeitsstate(thevalueofthefields,allofthemarefinal,andnosettersare exposed).ThismeansthatwhenwereturnaSeatobjecttotheclient(localorremote),it willbeonlyavailableforreading. Next,thesingletonbeanexposesfourpublicmethods;thegetSeatsmethodreturnsan unmodifiablecollectionofSeatobjects,whichwillreturntheinformationregarding whethertheyhavebeenreservedornottotheuser.Thecollectionmustbeunmodifiable becauseourSingletonexposesano-interfaceview,whichmeansthatweareusingthe pass-by-referencesemantic.Ifwewillnotprotectthecollection,theneverychangeonan elementofthereturnedcollectionwillbedoneonourcache.What’smore,theclientcan addorremoveelementstoourinternalcollection! ThegetSeatPricemethodisanutilitymethod,whichwillpickuptheseatpriceand returnitasint,soitcanbeusedtoverifywhethertheusercanaffordtobuytheticket. ThegetSeatmethodreturnsanimmutableSeatobjectforagivenID.Oncemore,we returnanimmutableSeatbecausewedon’twanttheclienttochangetheobjectwithout usingtheTheatherBoxbean. Finally,thebuyTicketmethodistheonethatactuallybuystheticketand,therefore,sets theticketasbooked.Wecannotchangethevalueofanimmutableobject,butwecan replaceitwithanewone,whichcontainsanothervalue.Thenewlycreatedobjectis placedinthehashmapinsteadoftheoldone. Controllingbeanconcurrency Asyoumighthavenoticed,thebeanincludesa@Lockannotationontopofthemethods managingourcollectionofSeatobjects.Thiskindofannotationisusedtocontrolthe concurrencyofthesingleton. ConcurrentaccesstoasingletonEJBis,bydefault,controlledbythecontainer. Read/writeaccesstoasingletonislimitedtooneclientatatime.However,itispossibleto provideafinerlevelofconcurrencycontrolthroughtheuseofannotations.Thiscanbe achievedusingthe@Lockannotation,whoseargumentsdeterminethetypeofconcurrency accesspermitted. [email protected],multithreadedaccess willbeallowedtothebean.Thisisshowninthefollowingcode: @Lock(READ) publicCollection<Seat>getSeats(){ returnCollections.unmodifiableCollection(seats.values()); } Ontheotherhand,ifweapplyjavax.ejb.LockType.WRITE,thesingle-threadedaccess policyisenforced,asshowninthefollowingcode: @Lock(WRITE) publicvoidbuyTicket(intseatId)throwsSeatBookedException, NoSuchSeatException{ finalSeatseat=getSeat(seatId); if(seat.isBooked()){ thrownewSeatBookedException(“Seat”+seatId+”already booked!”); } addSeat(seat.getBookedSeat()); } ThegeneralideaistouseREADtypelocksonmethodsthatjustreadvaluesfromthecache andWRITEtypelocksformethodsthatchangethevaluesofelementscontainedinthe cache.KeepinmindthatWRITEtypelocksblockallmethodswithREADtypelocks.Itis crucialthatthesingletonwillhaveexclusivecontrolofthemodificationsofitsstate.Lack ofproperencapsulationmixedwiththepass-by-referencesemantic(usedinlocalandnointerfaceviewsofEJBs)canleadtohard-to-findconcurrencybugs.Usingimmutable objectsasreturnvaluesforsingletonsisagoodstrategytosolvethesekindofproblems. Anotherstrategywouldbetoreturnonlycopiesofourobjectsorswitchingtothepass-byvaluesemantic.Thelaststrategycanbeappliedbyswitchingtoaremotebusiness interfaceinthesingleton. IntheTheatreBoxcode,youhaveprobablynoticeda@AccessTimeoutannotation(with value5andunitTimeUnit.MINUTES).Whenyouexecuteaqueryagainstamethodwith @Lock(WRITE),andifsomeotherthreadisalreadyaccessingit,thenafter5secondsof waiting,youwillgetatimeoutexception.Inordertochangethisbehavior(forexample, byprolongingtheallowedwaittime),[email protected] annotationatthemethodorclasslevel. Usingbean-managedconcurrency Theotherpossibleoptionistouseabean-managedconcurrencystrategythatcanbe pursuedbyapplyingthe@javax.ejb.ConcurrencyManagementannotationwithan argumentofConcurrencyManagementType.BEAN.Thisannotationwilldisabletheeffectof the@Lockannotationwehaveusedsofar,puttingtheresponsibilityofensuringthatthe singletoncachedoesnotgetcorruptedonthedeveloper. So,inordertoensurethatourbookingsarepreserved,wewillneedtouseawell-known synchronizedkeywordontopofthebuyTicketmethod,whichisasfollows: @Singleton @Startup @ConcurrencyManagement(ConcurrencyManagementType.BEAN) publicclassTheatreBox{ …. publicsynchronizedvoidbuyTicket(intseatId){ finalSeatseat=getSeat(seatId); if(seat.isBooked()){ thrownewSeatBookedException(“Seat”+seatId+”already booked!”); } addSeat(seat.getBookedSeat()); } Sinceconcurrentaccessisrestrictedwhenathreadentersthesynchronizedblock,noother methodsareallowedtoaccesstheobjectwhilethecurrentthreadisintheblock.Usinga synchronizedblockisequivalenttohavingacontainer-managedconcurrencywithdefault locksoftypeWRITEonallmethods.ThisisoneofthefewplacesinJavaEEwhenthe developermayusesynchronizationprimitiveswithoutaffectingthestabilityofthe container. Cookingsessionbeans OursingletonEJBisequippedwiththemethodstohandleourstoreoftheatreseats.We willnowaddacoupleofsessionbeanstoourprojecttomanagethebusinesslogic,a statelesssessionbeanthatwillprovideaviewofthetheatreseatsandstatefulbeansthat willbehaveasapaymentgatewaytooursystem. Note Thechoiceofsplittingourinformationsystemintotwodifferentbeansisnotpartofa designpatterninparticular,butservesadifferentpurpose.Thatis,wewouldliketoshow howtolookupbothtypesofbeansfromaremoteclient. Addingastatelessbean So,thefirstbeanwewillcreateis com.packtpub.wflydevelopment.chapter3.boundary.TheatreInfo,whichbarely containsthelogictolookupthelistoftheatreseats.Inpractice,thisbeanactsasafacade foroursingletonbean,asshowninthefollowingcode: @Stateless @Remote(TheatreInfoRemote.class) publicclassTheatreInfoimplementsTheatreInfoRemote{ @EJB privateTheatreBoxbox; @Override publicStringprintSeatList(){ finalCollection<Seat>seats=box.getSeats(); finalStringBuildersb=newStringBuilder(); for(Seatseat:seats){ sb.append(seat.toString()); sb.append(System.lineSeparator()); } returnsb.toString(); } } SinceweareplanningtoinvokethisEJBfromaremoteclient,wedefinedaremote interfaceforitwiththe@Remote(TheatreInfoRemote.class)annotation. Next,takealookatthe@EJBTheatreBoxbox,whichcanbeusedtosafelyinjectanEJB intoyourclasswithouttheneedofamanualJNDIlookup.Thispracticecanbeusedto increasetheportabilityofyourapplicationbetweendifferentapplicationservers,where differentJNDIrulesmightexist. Theremoteinterfaceofyourbeanwillbeassimpleasthefollowingcode: publicinterfaceTheatreInfoRemote{ StringprintSeatList(); } Note IfyouareplanningtoexposeyourEJBtolocalclientsonly(forexample,toaservlet), youcanleaveouttheremoteinterfacedefinitionandsimplyannotateyourbeanwith @Stateless.Theapplicationserverwillcreateano-interfaceviewofyoursessionbean, whichcansafelybeinjectedintoyourlocalclientssuchasservletsorotherEJBs.Be mindfulthatthisalsochangesthesemanticsofthemethodsparametersandreturnvalues. Forremoteviews,theywillbeserializedandpassedbyvalue. Addingastatefulbean Inordertokeeptrackofhowmuchmoneyourcustomerhasgotinhispocket,wewill needasession-awarecomponent.TurningaJavaclassintoastatefulsessionbeanisjusta matterofaddinga@Statefulannotationontopofit,asinourexample com.packtpub.wflydevelopment.chapter3.boundary.TheatreBookerclass.Thisis showninthefollowingcode: @Stateful @Remote(TheatreBookerRemote.class) @AccessTimeout(value=5,unit=TimeUnit.MINUTES) publicclassTheatreBookerimplementsTheatreBookerRemote{ privatestaticfinalLoggerlogger= Logger.getLogger(TheatreBooker.class); @EJB privateTheatreBoxtheatreBox; privateintmoney; @PostConstruct publicvoidcreateCustomer(){ this.money=100; } @Override publicintgetAccountBalance(){ returnmoney; } @Override publicStringbookSeat(intseatId)throwsSeatBookedException, NotEnoughMoneyException,NoSuchSeatException{ finalintseatPrice=theatreBox.getSeatPrice(seatId); if(seatPrice>money){ thrownewNotEnoughMoneyException(“Youdon’thaveenoughmoney tobuythis”+seatId+”seat!”); } theatreBox.buyTicket(seatId); money=money-seatPrice; logger.infov(“Seat{0}booked.”,seatId); return“Seatbooked.”; } } Asyoucansee,thepreviousbeanbearsa@PostConstructannotationtoinitializea sessionvariable(money)thatwillbeusedtocheckwhetherthecustomerhasenough moneytobuytheticket.WhenusingEJBs,wedon’tuseconstructorsanddestructors toperformactionsonanobjecttocreateordestroy.Thereasonisthatthepointobject mightnothaveinjectedallobjectsitdependson.Themethodannotatedwith @PostConstructisexecutedwhenobjectcreationisalreadyfinished,thatis,allobjects areinjectedtoit.ThereisasecondannotationrelatedtotheEJBlifecycle,@PreDestroy, whichisexecutedbeforetheobjectisdestroyed. Besidesthis,theultimatepurposeofourSFSBistoinvokethebuyTicketmethodofour singletonafterhavingperformedsomebusinesschecks. Ifthebusinesschecksdonotpass,theapplicationwillissuesomeexceptions.Thisisthe case,forexample,iftheseathasalreadybeenbookedorifthecustomerhasn’tgotenough moneytobuytheticket.Inordertokeepourconversationgoing,it’simportantthatour exceptionwillbeanextensionofthegenericExceptionclass.Refertothefollowingcode formoreinformation: publicclassSeatBookedExceptionextendsException{ //somecode } Ifweusearuntimeexception(forexample,EJBException),thebeaninstancewillbe discarded,andthecommunicationbetweentheremoteclientandserverwillbedropped. So,alwaystakecaretochoosetheappropriatetypeofexceptionwhendealingwithEJBs —choosetothrowaruntimeexceptionifyouaredealingwithanunrecoverablescenario (theconnectionwiththeenterpriseinformationsystemisdropped).Thiskindofexception iscalledaSystemException.Ontheotherhand,considerthrowingacheckedexception (orsimplynotthrowingexceptionsatall),ifyouaredealingwithabusinesskindof exception;forexample,ifthebookedseatisalreadyengaged.Recoverableexceptionsare calledApplicationExceptions. Thereisalsoapossibilitytomarkaruntimeexception(whichwouldnormallybea SystemException)asarecoverableexception,usingthe@ApplicationException annotation.Youmayevendecideifthecurrenttransactionshouldberolledback(whichis thedefaultbehaviorforsystemexceptions)using@ApplicationException(withrollback true)onanexceptionclassortheEJBContext.setRollbackOnlystatementinsidea businessmethod.Thedecisiontorollbackatransactionisuptothedeveloper,andin mostcases,itdependsonthebusinessscenario. DeployingtheEJBapplication Asitis,youshouldbeabletopackageyourEJBprojectbyissuingthefollowingMaven goalandstartingacommand-linepromptfromyourprojectroot: mvnpackage Theprecedingcommandwillcompileandpackagetheapplicationthatneedstobecopied intothedeploymentsfolderofyourapplicationserver.Thisisfine;however,wecan expectlotsmorefromMavenbyinstallingjustacoupleofplugins.Inourcase,wewill configureourprojecttouseMaven’sWildFlypluginbyaddingthefollowingsection: <build> <finalName>${project.artifactId}</finalName> <plugins> <!—WildFlyplugintodeploytheapplication—> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>1.0.2.Final</version> <configuration> <filename>${project.build.finalName}.jar</filename> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <!—enforceJava8—> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ejb-plugin</artifactId> <version>2.3</version> <configuration> <ejbVersion>3.2</ejbVersion> <!—Generateejb-clientforclientproject—> <generateClient>true</generateClient> </configuration> </plugin> </plugins> </build> InthefirstpartoftheXMLfragment,wespecifiedtheproject’sfinalNameattribute, whichwilldictatethenameofthepackagedartifact(inourexample,theproject’sname correspondstoourproject’sartifactID,soitwillbenamedticket-agency-ejb.jar). TheartifactIDnamedwildfly-maven-pluginwillactuallytriggertheWildFlyMaven pluginthatwillbeusedtodeployourproject. So,onceyouhaveconfiguredtheWildFlyplugin,yourapplicationcanbedeployed automaticallybyenteringfromyourprojectroot.Thiscanbedonebytypingthefollowing commandintheconsole: mvnwildfly:deploy Sincedeploymentisarepetitivetaskforadeveloper,itwouldbeconvenienttoexecute thisoperationfromwithintheEclipseenvironment.AllyouneedistocreateanewRun ConfigurationssettingfromtheuppermenubynavigatingtoRun|RunConfigurations. Entertheproject’sbasedirectory(hint:theBrowseWorkspace…utilitywillhelpyou pickuptheprojectfromyourprojectlist)andtypeyourMavengoalintotheGoals textbox,asshowninthefollowingscreenshot: Oncethisisdone,pleaseensurethatyourWildFlyinstanceisrunning.ClickonApplyto saveyourconfigurationandthenclickonRuntoexecutethedeploymentofthe application.TheMavenpluginwillactivateandonceitisverifiedthatallclassesareupto date,startdeployingtheapplicationstoWildFlyusingtheremoteAPI.Notethatyoudo notneedtopassanyusernameorpasswordforthedeployment.Thisispossiblebecause youaredeployingyourapplicationfromthesamemachinethatWildFlyisinstalledon.A localuserauthenticationisdoneunderthehoodsothatprogrammerswillnotneedto coverthisontheirdevelopmentmachines. Afterissuingthecommand,youshouldexpectasuccessmessageontheMavenconsole, asshowninthefollowingcode: INFO:JBossRemotingversion4.0.3.Final [INFO]––––––––––––––––––––– [INFO]BUILDSUCCESS [INFO]––––––––––––––––––––– Ontheotherhand,ontheWildFlyconsole,youhavequiteaverboseoutputthatpointsout someimportantEJBJNDIbindings(wewillreturntoitinaminute)andinformsusthat theapplicationhasbeendeployedcorrectly.Thisisdepictedinthefollowingcode: 09:09:32,782INFO[org.jboss.as.server](management-handler-thread-1) JBAS018562:Deployed“ticket-agency-ejb.jar” DespitethefactthatweareworkingonWildFly,wecanquitefrequentlyseeinformation fromJBossASsubsystemsontheconsole.ThisisbecauseWildFlyisbuiltstraightonthe JBossAS7codebase,andshouldnotbeworriedabout. CreatingaremoteEJBclient CreatingaremoteEJBclientfortheWildFlyapplicationserverisverysimilartoAS7. ThebigdifferencecanbenoticedbetweenAS6andnewerreleases. Asamatteroffact,previousversionsofWildFly(JBossASversionsbefore7.x)usedthe JBossnamingprojectastheJNDInamingimplementation,sodevelopersarefamiliarwith jnp://PROVIDER_URLtocommunicatewiththeapplicationserver. StartingwithAS7,theJNPprojectisnolongerused—neitherontheserversidenoronthe clientside.TheclientsideoftheJNPprojecthasnowbeenreplacedbythejboss-remotenamingproject.TherewerevariousreasonswhytheJNPclientwasreplacedbythejbossremote-namingproject.OneofthemwasthattheJNPprojectdidnotallowfine-grained securityconfigurationswhilecommunicatingwiththeJNDIserver.Thejboss-remotenamingprojectisbackedbythejboss-remotingprojectwhichallowsmuchmoreand bettercontroloversecurity. BesidesthenewnamingimplementationinAS7andWildFly,thereisnolongerany supporttobindcustomJNDInamestoEJBs.Sothebeansarealwaysboundtothespec’s mandatedjava:global,java:app,andjava:modulenamespaces.Therefore,settingthe JNDInameforthesessionbeanelementviaanannotationorconfigurationfileisno longersupported. So,whatwillbetheJNDInameusedtoinvokeastatelesssessionbean?Hereitis: ejb:<app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualifiedclassname-of-the-remote-interface> Abitverbose,isn’tit?However,thefollowingtablewillhelpyougetthroughit: Element Description app-name Thisistheenterpriseapplicationname(withoutear),ifyourEJBhasbeenpackedinanEAR module-name Thisisthemodulename(without.jaror.war),whereyourEJBhasbeenpacked distinct-name Usingthis,youcanoptionallysetadistinctnameforeachdeploymentunit bean-name Thisisthebean’sclassname fully-qualified-classname-of-the-remote-interface Thisisthefullyqualifiedclassnameoftheremoteinterface SothecorrespondingJNDIbindingforyourTheatreInfoEJB,packagedintoafile namedticket-agency-ejb.jar,willbe: ejb:/ticket-agency-ejb//TheatreInfo! com.packtpub.wflydevelopment.chapter3.boundary.TheatreInfoRemote Ontheotherhand,statefulEJBswillcontainonemoreattribute,?stateful,atthebottom oftheJNDIstring;thiswillresultinthefollowingJNDInamingstructure: ejb:<app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualifiedclassname-of-the-remote-interface>?stateful Also,here’sthecorrespondingbindingfortheTheatreBookerclass: ejb:/ticket-agency-ejb//TheatreBooker! com.packtpub.wflydevelopment.chapter3.boundary.TheatreBookerRemote?stateful Note Ifyoupayattentiontotheserverlogs,youwillseethatonceyourapplicationisdeployed, asetofJNDIbindingswillbedisplayedontheserverconsole.Forexample: java:global/ticket-agencyejb/TheatreInfo!com.packtpub.wflydevelopment.chapter3.boundary.TheatreInfoRemote java:app/ticket-agencyejb/TheatreInfo!com.packtpub.wflydevelopment.chapter3.boundary.TheatreInfoRemote java:module/TheatreInfo!com.packtpub.wflydevelopment.chapter3.boundary.TheatreInf java:jboss/exported/ticket-agencyejb/TheatreInfo!com.packtpub.wflydevelopment.chapter3.boundary.TheatreInfoRemote SomeofthesebindingsreflectthestandardbindingsasperJavaEEspecificationsplus JBosscustombindings(java:/jboss).Thisinformation,asitis,isnotrelevantforusbut canbeusetobuildourEJBclientlookupstringbyreplacingtheJavaEE(orJBossspecificprefix)withejb:/.Forexample,replacejava:/globalwithejb:,andyouwill saveyourselftheheadacheofreferringtotheEJBlookupstring. OncewearedonewithdecodingtheJNDIbindingstring,wewillcodeourEJBclient.We havealreadycreatedaseparatesubprojectforit(ticket-agency-ejb-client)atthe beginningofthischapter,butwemuststillcompleteitsconfigurationbeforewediveinto coding. Configuringtheclient’sprojectobjectmodule Configuringtheclientdependencies(inpom.xml)willbasicallyrequireallthelibraries thatconnectandtransportdatatotheserver,alongwiththerequiredEJBclient dependencies.Thefirstthingwewilladd,justaswedidfortheserverproject,istheBOM fortheEJBclientdependencies,whichisdemonstratedinthefollowingcodesnippet: <dependencyManagement> <dependencies> <dependency> <groupId>org.wildfly</groupId> <artifactId>wildfly-ejb-client-bom</artifactId> <version>8.1.0.Final</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> Next,wewilladdasetofdependenciesthatareneededtoresolvetheEJBinterfaces (ticket-agency-ejbartifact),theJBoss’transactionAPI(neededasEJBsare transaction-awarecomponents),thejboss-ejb-apiandejb-clientAPIs,the org.jboss.xnioandorg.jboss.xnioAPIs(whichprovidealow-levelinput/output implementation),theorg.jboss.remoting3API(thecoretransportprotocol),whichin turnrequiresorg.jboss.sasl(tosecurethetransport),andfinally,the org.jboss.marshallingAPI(toserializetheobjectsthataresenttoandreceivedfrom theserver).Thisisshowninthefollowingcodesnippet: <dependencies> <dependency> <groupId>com.packtpub.wflydevelopment.chapter3</groupId> <artifactId>ticket-agency-ejb</artifactId> <type>ejb-client</type> <version>${project.version}</version> </dependency> <dependency> <groupId>org.jboss.spec.javax.transaction</groupId> <artifactId>jboss-transaction-api_1.2_spec</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.jboss.spec.javax.ejb</groupId> <artifactId>jboss-ejb-api_3.2_spec</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.jboss</groupId> <artifactId>jboss-ejb-client</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.jboss.xnio</groupId> <artifactId>xnio-api</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.jboss.xnio</groupId> <artifactId>xnio-nio</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.jboss.remoting3</groupId> <artifactId>jboss-remoting</artifactId> <version>3.3.3.Final</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.jboss.sasl</groupId> <artifactId>jboss-sasl</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.jboss.marshalling</groupId> <artifactId>jboss-marshalling-river</artifactId> <scope>runtime</scope> </dependency> </dependencies> Manyofthesedependenciesusetheruntimescope.Thismeansthatclassesthatare providedbythemarenotuseddirectlybyourcode;theyarenotneededtobebundled withinourapplicationpackage,buttheyarerequiredatruntime. CodingtheEJBclient Wearedonewiththeconfiguration.WewillfinallyproceedwithaddinganewJavaclass com.packtpub.wflydevelopment.chapter3.client.TicketAgencyClient,whichwill communicatewiththeticketbookingmachine’sEJBapplication.Thisisshowninthe followingcodesnippet: publicclassTicketAgencyClient{ privatestaticfinalLoggerlogger= Logger.getLogger(TicketAgencyClient.class.getName()); publicstaticvoidmain(String[]args)throwsException{ Logger.getLogger(“org.jboss”).setLevel(Level.SEVERE);[1] Logger.getLogger(“org.xnio”).setLevel(Level.SEVERE); newTicketAgencyClient().run(); } privatefinalContextcontext; privateTheatreInfoRemotetheatreInfo; privateTheatreBookerRemotetheatreBooker; publicTicketAgencyClient()throwsNamingException{ finalPropertiesjndiProperties=newProperties();[2] jndiProperties.setProperty(Context.URL_PKG_PREFIXES, “org.jboss.ejb.client.naming”); this.context=newInitialContext(jndiProperties); } privateenumCommand{[3] BOOK,LIST,MONEY,QUIT,INVALID; publicstaticCommandparseCommand(StringstringCommand){ try{ returnvalueOf(stringCommand.trim().toUpperCase()); }catch(IllegalArgumentExceptioniae){ returnINVALID; } } } privatevoidrun()throwsNamingException{ this.theatreInfo=lookupTheatreInfoEJB();[4] this.theatreBooker=lookupTheatreBookerEJB();[5] showWelcomeMessage();[6] while(true){ finalStringstringCommand=IOUtils.readLine(“>“); finalCommandcommand=Command.parseCommand(stringCommand); [7] switch(command){ caseBOOK: handleBook(); break; caseLIST: handleList(); break; caseMONEY: handleMoney(); break; caseQUIT: handleQuit(); break; default: logger.warning(“Unknowncommand”+stringCommand); } } } privatevoidhandleBook(){ intseatId; try{ seatId=IOUtils.readInt(“EnterSeatId:“); }catch(NumberFormatExceptione1){ logger.warning(“WrongSeatIdformat!”); return; } try{ finalStringretVal=theatreBooker.bookSeat(seatId); System.out.println(retVal); }catch(SeatBookedException|NotEnoughMoneyException| NoSuchSeatExceptione){ logger.warning(e.getMessage()); return; } } privatevoidhandleList(){ logger.info(theatreInfo.printSeatList()); } privatevoidhandleMoney(){ finalintaccountBalance=theatreBooker.getAccountBalance(); logger.info(“Youhave:”+accountBalance+”moneyleft.”); } privatevoidhandleQuit(){ logger.info(“Bye”); System.exit(0); } privateTheatreInfoRemotelookupTheatreInfoEJB()throwsNamingException { return(TheatreInfoRemote)context.lookup(“ejb:/ticket-agencyejb//TheatreInfo!com.packtpub.wflydevelopment.chapter3.boundary.TheatreInfoRemote } privateTheatreBookerRemotelookupTheatreBookerEJB()throws NamingException{ return(TheatreBookerRemote)context.lookup(“ejb:/ticket-agencyejb//TheatreBooker!com.packtpub.wflydevelopment.chapter3.boundary.TheatreBookerRe stateful”); } privatevoidshowWelcomeMessage(){ System.out.println(“Theatrebookingsystem”); System.out.println(“=====================================”); System.out.println(“Commands:book,list,money,quit”); } } Let’sseethemostinterestingpoints.First,inthemainfunction,wesetsomeloggingrules [1]inordertoavoidmixingtheJBossremotinglogmessageswiththeconsole applicationinformation. Next,wecreatetheTicketAgencyClientobjectandexecuteitsrunmethod.During objectcreation,wepreparetheInitialContextobject(furtherusedtolookupremote objects).Todothis,wewillneedasetof[2]properties,whichspecifywhattypeofejbclientisused. In[3],wedefineaCommandenum,whichrepresentsconsolecommandsthatuserscan sendtothisapplication.Therun()methodfirstperformsthelookupoftheSLSBand SFSB([4]and[5])remoteEJBs,andthenshowsthewelcomemessage([6]).Inthe infiniteloop,wewaitfortheusertoenteracommandandparseit([7]).Dependingonthe user’schoicewecanbookaseat,listseats’information,getavailablemoney,orquitthe application. AddingtheEJBclientconfiguration Asyoucanseefromtheprecedingcodesnippet,thereisnoindicationaboutthelocation oftheserverwheretheEJBsarerunning.Itispossibletospecifythisbycode,butinthis sample,wewillchoosethesimplerwayandaddjboss-ejb-client.propertiesfilein theclient’sclasspath. Note InMaven,theappropriatelocationformostoftheresourcefiles(likementioned properties)isthesrc/main/resourcesdirectory. Thecontentsofthejboss-ejb-client.propertiesfileareasfollows: remote.connections=default remote.connection.default.host=localhost remote.connection.default.port=8080 Thereisalsoaremote.connectionprovider.create.options.org .xnio.Options.SSL_ENABLEDproperty,whichenablestheencryptionoftheXNIO connection;otherwise,plaintextwillbeused.(InChapter10,SecuringWildFly Applications,wewilldiscussusingSSLtosecuretheconnectionbetweentheclientand server.) Theremote.connectionspropertycanbesettodefinealistoflogicalnamesthatwillbe usedforconnectionpurposesbytheremote.connection.[name].hostand remote.connection.[name].portattributes.Ifyoudefinemorethanoneconnection,as inthefollowingexample,theconnectionswillbesplitacrossvariousdestinations,as showninthefollowingcodesnippet: remote.connections=host1,host2 remote.connection.host1.host=192.168.0.1 remote.connection.host2.host=192.168.0.2 remote.connection.host1.port=8080 remote.connection.host2.port=8080 Thedefaultportusedbytheremotingframeworkis8080. YoumaywonderhowEJBremotingcanworkonthesameportastheHTTPprotocol. StartingfromWildFly,remotingusestheHTTPprotocolupgrademechanism.Thefirst connectionisdoneonthe8080port(viaHTTP),thenitisupgradedtoEJBremoting,and switchedtoanotherport(chosenbyWildFly). Runningtheclientapplication Inordertorunyourclientapplication,thelastrequirementwillbetoaddtherequired Mavenplugins,whichareneededtoruntheremoteEJBclient.Thisisgiveninthe followingcodesnippet: <build> <finalName>${project.artifactId}</finalName> <plugins> <!—maven-compiler-pluginhere—> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.2.1</version> <executions> <execution> <goals> <goal>exec</goal> </goals> </execution> </executions> <configuration> <executable>java</executable> <workingDirectory>${project.build.directory}/exec-workingdirectory</workingDirectory> <arguments> <argument>-classpath</argument> <classpath/> <argument>com.packtpub.wflydevelopment.chapter3.client.TicketAgencyClient</argume </arguments> </configuration> </plugin> </plugins> </build> Asyoucanseeintheprecedingcodesnippet,besidesthemaven-compiler-plugin configurationthatweomittedforthesakeofbrevity(wediscusseditintheserver project),wehaveincludedexec-maven-plugin,whichaddstheabilitytoexecuteJava programsusingtheexecgoal. Onceallthepluginsareinplace,youcancompileandexecuteyourprojectbyissuingthe followingMavengoal: mvnpackageexec:exec Theprecedingcommandcanbeexecutedeitherfromashell(positionedintheproject’s rootfolder)orfromyourEclipseruntimeconfiguration,asshowninthefollowing screenshot: IfexecutedfromtheEclipseenvironment,youshouldbeabletoseethefollowingGUI screenshot: Atthemoment,ourapplicationprovidesthreefunctions:abooktobookaseat,alisttolist allthetheatreseats,andmoneytoretrievetheaccountbalance.Inthenextsections,we willenrichourapplicationbyaddingsomemorecommands. Addinguserauthentication Ifyouarerunningthisexamplefromaclientthatislocatedonthesamemachineasthe applicationserver,theremotingframeworkwillsilentlyallowcommunicationbetweenthe clientandyourEJB’sclasses.Ontheotherhand,foraclientlocatedonaremotesystem, youwillberequiredtoprovideauthenticationforyourrequests.Inordertoaddan applicationuser,launchtheadd-user.sh(oradd-user.bat)script,whichislocatedat JBOSS_HOME/bin. Here’satranscriptofausercreationexample: Whattypeofuserdoyouwishtoadd? a)ManagementUser(mgmt-users.properties) b)ApplicationUser(application-users.properties) (a):b Enterthedetailsofthenewusertoadd. Usingrealm‘ApplicationRealm’asdiscoveredfromtheexistingproperty files. Username:ejbuser Passwordrequirementsarelistedbelow.Tomodifytheserestrictionsedit theadd-user.propertiesconfigurationfile. -Thepasswordmustnotbeoneofthefollowingrestrictedvalues{root, admin,administrator} -Thepasswordmustcontainatleast8characters,1alphanumeric character(s),1digit(s),1non-alphanumericsymbol(s) -Thepasswordmustbedifferentfromtheusername Password: Re-enterPassword: Whatgroupsdoyouwantthisusertobelongto?(Pleaseenteracomma separatedlist,orleaveblankfornone)[]: Abouttoadduser‘ejbuser’forrealm‘ApplicationRealm’ Isthiscorrectyes/no?yes Addeduser‘ejbuser’tofile‘C:\Programs\Dev\Servers\wildfly8.0.0.Final\standalone\configuration\application-users.properties’ Addeduser‘ejbuser’tofile‘C:\Programs\Dev\Servers\wildfly8.0.0.Final\domain\configuration\application-users.properties’ Addeduser‘ejbuser’withgroupstofile‘C:\Programs\Dev\Servers\wildfly8.0.0.Final\standalone\configuration\application-roles.properties’ Addeduser‘ejbuser’withgroupstofile‘C:\Programs\Dev\Servers\wildfly8.0.0.Final\domain\configuration\application-roles.properties’ IsthisnewusergoingtobeusedforoneASprocesstoconnecttoanother ASprocess? e.g.foraslavehostcontrollerconnectingtothemasterorforaRemoting connectionforservertoserverEJBcalls. yes/no?no Pressanykeytocontinue… Thedefineduserwillbeaddedforyouintheapplication-user.propertiesfilelocated inyourconfigurationfolder. ThisfilecontainsthedefaultsecurityrealmnamedApplicationRealm.Thissecurity realmusesthefollowingformattostorepasswords: username=HEX(MD5(username‘:’realm‘:’password)) Withthepasswordsyou’vejustentered,thefilewillcontainthefollowingentry: ejbuser=dc86450aab573bd2a8308ea69bcb8ba9 Now,inserttheusernameandpasswordinformationintojboss-ejb-client.properties: remote.connection.default.username=ejbuser remote.connection.default.password=ejbuser123 Now,withallthepreviousinformationintherightplace,youwillbeabletoconnectto yourEJBapplicationfromaclientthatdoesnotresideonthesamemachineastheserver. Youcanalsoforcethenormalauthenticationprocessonyourlocalmachine,byaddingthe followinglinetothejboss-ejb-clientproperties: remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHAN LOCAL-USER UsingtheEJBtimerservice Applicationsthatmodelbusinessworkflowsoftenrelyontimednotifications.Thetimer serviceoftheenterprisebeancontainerenablesyoutoscheduletimednotificationsforall typesofenterprisebeans,exceptforstatefulsessionbeans.Youcanscheduleatimed notificationtooccuraccordingtoacalendarscheduleeitherataspecifictime,afterthe durationofatimeperiod,orattimedintervals. TherecanbetwomaintypesofEJBtimers:programmatictimersandautomatictimers. Programmatictimersaresetbyexplicitlycallingoneofthetimercreationmethodsofthe TimerServiceinterface.Automatictimersarecreateduponthesuccessfuldeploymentof anenterprisebean,whichcontainsamethodannotatedwiththejava.ejb.Scheduleor java.ejb.Schedulesannotations.Let’sseebothapproachesinthefollowingsections. Programmatictimercreation Tocreateatimer,thebeaninvokesoneofthecreatemethodsoftheTimerService interface.Thesemethodsallowforeithersingle-action,interval,orcalendar-basedtimers tobecreated. ThesimplestwaytogetaTimerServiceinstanceistouseresourceinjection.For example,intheTheatreBoxsingletonEJB,wewillusethe@Resourceannotationtoinject aTimerServiceobject,asshowninthefollowingcodesnippet: @Resource TimerServicetimerService; privatestaticfinallongDURATION=TimeUnit.SECONDS.toMillis(6); Thedurationspecifiesthetime(inmilliseconds)whenthesingletimerisfired.The methodthatwillfirethetimerwillusetheTimerServiceinstancetoinvoke createSingleActionTimer,passingthedurationandaninstanceoftheTimerConfigclass asanargument,whichmayoptionallycontainsomebasicinformation(suchasthe descriptionofthetimer).Thisisshowninthefollowingcodesnippet: publicvoidcreateTimer(){ timerService.createSingleActionTimer(DURATION,newTimerConfig()); } Next,wewillcreateacallbackmethodnamedtimeoutandusethe@Timeoutannotation ontopofthemethod.Inthetimeoutmethod,wecould,forexample,reinitializeour singletonbyinvokingthesetupTheatremethod.Nothingfancy;however,thisshould giveyouanideaofhowtogetworkingwithasingleactiontimer.Refertothefollowing codeformoreinformation: @Timeout publicvoidtimeout(Timertimer){ logger.info(“Re-buildingTheatreMap.”); setupTheatre(); } Schedulingtimerevents Ifyouwanttoscheduletimednotificationsatfixedintervals,thesimplestwayistousethe @Scheduleannotation.The@Scheduleannotationtakesaseriesofcomma-delimited settingstoexpressatimeperiodorsetoftimeperiods,muchastheUnixcronutilitydoes. Eachsettingcorrespondstoaunitoftimesuchasanhourorminute.Asimplerepeating eventoccurringeveryminutecanbeexpressedusingthe@Scheduleannotationasfollows: @Schedule(second=“0”,minute=“*”,hour=“*”) Youcanfindsomemoredetailsaboutbuildingthetimestringat. Forthepurposeofourexample,wewillcreateastatelesssessionbean,whichwillactas anautomaticbuyingsystemandtherefore,buyticketsatourticketingstore.So,wewill addonecompetitorinourquestforthebestseatinthetheatre!Thefollowingcodesnippet explainsthis: @Stateless publicclassAutomaticSellerService{ privatestaticfinalLoggerlogger= Logger.getLogger(AutomaticSellerService.class); @EJB privateTheatreBoxtheatreBox; @Resource privateTimerServicetimerService;[1] @Schedule(hour=“*”,minute=“*/1”,persistent=false)[2] publicvoidautomaticCustomer()throwsNoSuchSeatException{ finalOptional<Seat>seatOptional=findFreeSeat(); if(!seatOptional.isPresent()){ cancelTimers(); logger.info(“Schedulergone!”); return;//Nomoreseats } finalSeatseat=seatOptional.get(); try{ theatreBox.buyTicket(seat.getId());[3] }catch(SeatBookedExceptione){ //donothing,userbookedthisseatinthemeantime } logger.info(“Somebodyjustbookedseatnumber”+seat.getId()); } privateOptional<Seat>findFreeSeat(){ finalCollection<Seat>list=theatreBox.getSeats(); returnlist.stream() .filter(seat->!seat.isBooked()) .findFirst(); } privatevoidcancelTimers(){[4] for(Timertimer:timerService.getTimers()){ timer.cancel(); } } } ThefirstthingweshouldaccountforistheresourceinjectionoftheTimerobject[1], whichwillbeusedinthecancelTimersmethod[4]tocancelalltheschedulingwhenthe theatreisfullybooked.PleasenotethatthetimerService.getTimers()methodretrieves allactivetimersassociatedonlywiththecurrentbean.Inordertogetalltimersfromyour applicationmodule,youhavetousethetimerService.getAllTimers()method,which wasaddedrecentlyinEJB3.2. Next,payattentiontotheScheduleannotation[2]weareusing,whichwillfireanonpersistenttimereachminute. Note Persistenttimers(thedefaultoption)cansurviveapplicationandservercrashes.Whenthe systemrecovers,anypersistenttimerswillberecreatedandmissedcallbackeventswillbe executed. Whenareplayofmissedtimereventsisnotdesired,anon-persistenttimershouldbeused, asshownintheprecedingexample. Whenanactionisfired,theautomaticCustomermethodstartsscanningthetheatreseats foranavailableseat.(Nothingtoocomplex;findSeatstartslookingfromthefirst availableseat.) Finally,ifthereareseatsstillavailable,thebuyTicketmethod[3]oftheTheatreBox singletonwillbeusedtoshortcircuitthepurchaseoftheseat(obviously,wewon’tneedto checkthemoneyforourautomaticcustomer). AddingasynchronousmethodstoourEJBs BeforetheEJB3.1specification,theonlywaytoprovideasynchronouscapabilitiesto enterpriseapplicationswasusingmessage-drivenbeanrecipes.Thisremainssubstantially abestpractice,andwearegoingtodiscussthisindepthinChapter6,Developing ApplicationswithJBossJMSProvider;however,insomecases,itmightbedesirable(and easier)tousetheseasynchronousfeaturesfromacomponentthatfollowstheclassical request-replypattern. YoucanmaketheEJB’smethodasynchronousbysimplytaggingitwiththe @Asynchronousannotation.Eachtimethismethodisinvoked,itwillimmediatelyreturn, regardlessofhowlongthemethodactuallytakestocomplete. Thiscanbeusedinoneoftwoways: Thefirsttechniqueisafire-and-forgetmanner,wheretherequestismadeupofthe EJBandtheclientisnotconcernedaboutthesuccessorfailureoftherequest. Thesecondmodusoperandiinvokesthemethodbutdoesnotwaitforthemethodto becompleted.ThemethodreturnsaFutureobject.Thisobjectisusedlaterto determinetheresultoftherequest. Usingfire-and-forgetasynchronouscalls Ifyoudon’tcareabouttheasyncresult,youcanjusthaveyourasyncmethodreturnvoid. Forthispurpose,wewilladdanewmethodnamedbookSeatAsynctoTheatreBookerand [email protected]: @Asynchronous publicvoidbookSeatAsync(intseatId)throwsNotEnoughMoneyException, NoSuchSeatException,SeatBookedException{ bookSeat(seatId); } Asyoucansee,thismethoddoesnotreturnanything;itjustexecutesoursynchronous bookSeetmethod.Wewillneedtousesomeotherinstrumentstocheckwhetherthe transactionwascompletedsuccessfully.Forexample,wecancheckfromthetheatrelist whethertheseathasbeenbookedsuccessfully. ReturningaFutureobjecttotheclient Theotheravailableoptionconsistsofreturningajava.util.concurrent.Futureobject, whichcanlaterbeinspectedbyourclientssothattheyknowtheoutcomeofour transaction.Thisisshowninthefollowingcodesnippet: @Asynchronous @Override publicFuture<String>bookSeatAsync(intseatId){ try{ Thread.sleep(10000); bookSeat(seatId); returnnewAsyncResult<>(“Bookedseat:”+seatId+“.Money left:”+money); }catch(NoSuchSeatException|SeatBookedException| NotEnoughMoneyException|InterruptedExceptione){ returnnewAsyncResult<>(e.getMessage()); } } Inthiscase,callstotheasynchronousbookSeatAsyncmethodsimplyresults,behindthe scenes,inaRunnableorCallableJavaobjectbeingcreated,whichwrapsthemethod andparametersyouprovide.ThisRunnable(orcallable)objectisgiventoanExecutor object,whichissimplyaworkqueueattachedtoathreadpool. Afteraddingtheworktothequeue,theproxyversionofthemethodreturnsaFuture implementationthatislinkedtoRunnable,whichisnowwaitinginthequeue. WhenRunnablefinallyexecutesthebookSeatAsyncmethod,ittakesthereturnvalueand setsittoFuture,makingitavailabletothecaller. WhendealingwithFutureobjects,theclientcodeneedstobeadapted.Asamatterof fact,instandardsynchronouscalls,weusedexceptionstointerceptsomeeventssuchas whenthecustomerdoesnothaveenoughmoneytocompletethetransaction.Whenusing Futurecalls,there’sachangeinthisparadigm.Thecalltotheasynchronousmethodis detachedfromtheclient;however,wehavetheoptiontocheckiftheFutureworkhas beencompletedwiththeisDonemethodissuedontheFuturereturnvalue. Forthispurpose,let’saddabookasynccommandtoTicketAgencyClient,whichwill issueasynchronousbookingandamailcommandthatwillsimulatethereadingofthe outcomebye-mail,asshowninthefollowingcodesnippet: privatefinalList<Future<String>>lastBookings=newArrayList<>();[1] //Somecode caseBOOKASYNC: handleBookAsync(); break; caseMAIL: handleMail(); break; //Somecode privatevoidhandleBookAsync(){ Stringtext=IOUtils.readLine(“EnterSeatId:“); intseatId; try{ seatId=Integer.parseInt(text); }catch(NumberFormatExceptione1){ logger.warning(“WrongseatIdformat!”); return; } lastBookings.add(theatreBooker.bookSeatAsync(seatId));[2] logger.info(“Bookingissued.Verifyyourmail!”); } privatevoidhandleMail(){ booleandisplayed=false; finalList<Future<String>>notFinished=newArrayList<>(); for(Future<String>booking:lastBookings){ if(booking.isDone()){[3] try{ finalStringresult=booking.get(); logger.info(“Mailreceived:”+result); displayed=true; }catch(InterruptedException|ExecutionExceptione){ logger.warning(e.getMessage()); } }else{ notFinished.add(booking); } } lastBookings.retainAll(notFinished); if(!displayed){ logger.info(“Nomailreceived!”); } } Asyoucanseefromthepreviouscodesnippet,weissueanasynchronousbooking[2] andaddFuture<?>tolastBookingslist[1].OntheEJBside,weintroducedapauseof 10secondstocompletethebookingsothatlateron,wecancheckiftheworkhasbeen completedbycheckingtheisDonemethod[3]ofthelastBookingslistelementsobject. Hereisascreenshotofourricherclientapplication: Summary Inthischapter,wewentthroughtheEJBbasicsandchangesinEJB3.2byfollowinga simplelabexample,whichwasenrichedprogressively.Thisexampleshowedhowthe MavenprojectcanbeusedfromwithintheEclipseenvironmenttoassistyouin assemblingtheprojectwithallthenecessarydependencies. Uptonow,wehavejustcodedaremotestandaloneclientforourapplication.Inthenext chapter,wewillseehowtoaddawebfrontendtoourexampleusingthecontextand dependencyinjections,tobridgethegapbetweenthewebtierandenterprisetier. Chapter4.LearningContextand DependencyInjection WesawthatChapter3,IntroducingJavaEE7–EJBs,waschallengingsincewehadto coverlotsofground,includingJavaEnterpriseenhancementsandaMaven-specific configuration.Inthischapter,we’lldiscussContextsandDependencyInjection(CDI), whichwasaddedtotheJavaEEspecificationinJavaEE6(startingfromJSR299).It providesseveralbenefitstoJavaEEdevelopersthatweremissing,suchasallowingany JavaBeantobeusedasaJSFmanagedbean,includingstatelessandstatefulsessionbeans. YoucanfindmoreinformationonCDIandthenewestversionofthespecificationitself (JSR346)athttp://www.cdi-spec.org/. Someofthetopicsthatwillbecoveredinthischapterareasfollows: WhatContextsandDependencyInjectionisandhowitrelatestoEJB Howtorewriteourticket-bookingexampletousetheCDIandJavaServerFaces technology HowtoruntheprojectusingMaven ThischapterassumesfamiliaritywithJavaServerFaces(JSF),whichwillbeusedto provideagraphicalinterfaceforourapplications.Ifyouarelookingforastartupguide forJSF,thereareseveralexcellentresourcesavailableonline,includingtherelevant sectionsintheofficialJavaEE7tutorialat http://docs.oracle.com/javaee/7/tutorial/doc/jsf-develop.htm#BNATX. IntroducingContextsandDependency Injection CDIfortheJavaEEplatformintroducesastandardsetofcomponentmanagement servicestotheJavaEEplatform.AsacomponentofJavaEE7,CDIisinmanywaysa standardizationofconceptsthathavebeenbrewinginSpringforalongtime,suchas dependencyinjectionandinterceptors.Infact,CDIandSpring3sharemanysimilar features.Therearealsootherdependencyinjectionframeworksavailablefordevelopers thataremorelightweightandeasiertouseinaJavaSEenvironment.GoogleGuice (https://github.com/google/guice)isanotableexample.Providingfull-blownsupportfor theCDIcontainerinastandaloneJavaSEapplicationandseparationfromtheapplication serverareoneofthegoalsoftheupcomingCDI2.0specification.Thiswillallow developerstouseacommonprogrammingmodelonbothclientandserversides. CDIletsyoudecoupleconcernsbywhatitreferstoasloosecouplingandstrongtyping.In doingso,itprovidesanalmostliberatingescapefromthebanalitiesofeverydayJava programming,allowinginjectionsofitsobjectsandcontrollingtheirlifetimes. Tip WhyisCDIrequiredforJavaEE? IfyouhavebeenprogrammingwithJavaEE5,youmightarguethatitalreadyfeatures resourcesinjectionofresources.However,thiskindofinjectioncanbeusedonlyfor resourcesknowntothecontainer(forexample,@EJB,@PersistenceContext, @PersistenceUnit,and@Resource).CDI,ontheotherhand,providesageneral-purpose dependencyinjectionscheme,whichcanbeusedforanycomponent. TheCDIelementaryunitisstillthebean.ComparedtoEJBs,CDIfeaturesadifferent, moreflexiblekindofbean,whichwouldoftenbeagoodplacetoputyourbusinesslogic in.OneofthemostimportantdifferencesbetweenthetwoapproachesisthatCDIBeans arecontextual;thatis,theyliveinawell-definedscope. Considerthefollowingcodesnippet: publicclassHelloServletextendsHttpServlet{ @EJB privateEJBSampleejb; publicvoiddoGet(HttpServletRequestreq, HttpServletResponseres) throwsServletException,IOException{ try(PrintWriterout=res.getWriter()){ out.println(ejb.greet()); } } } Here,theinjectedEJBproxy(let’sjustassumethatitisaPOJOclassannotatedwitha @Statelessannotation)justpointstoapoolofstatelessinstances(orasinglebean instanceforstatefulbeans).ThereisnoautomaticassociationbetweentheHTTPrequest orHTTPsessionandagivenEJBinstance. TheoppositeistrueforCDIBeans,whichliveinwell-definedscopes.Forexample,the followingCDIBeanlivesinRequestScoped;thatis,itwillbedestroyedattheendofthe request: @RequestScoped publicclassCustomer{ privateStringname; privateStringsurname; publicStringgetName(){ returnname; } publicStringgetSurname(){ returnsurname; } } TheprecedingCDIBeancanbesafelyinjectedintoourformerservlet;attheendofan HTTPsessionorHTTPrequest,alltheinstancesassociatedwiththisscopeare automaticallydestroyed,andthus,garbagecollected: publicclassHelloServletextendsHttpServlet{ @Inject privateCustomercustomer; publicvoiddoGet(HttpServletRequestreq, HttpServletResponseres) throwsServletException,IOException{ //somecode } } Namedbeans Intheearliersection,[email protected] easilyinjectourbeansintootherclassesthatdependonthemandrefertothemfromJSF pagesviatheUnifiedExpressionLanguage(UEL).Recalltheearlierexample: @RequestScoped @Named publicclassCustomer{ privateStringname; privateStringsurname; publicStringgetName(){ returnname; } publicStringgetSurname(){ returnsurname; } } Thisclass,decoratedwiththe@Namedannotation,canthenbereferencedfromaJSFpage: <?xmlversion=“1.0”encoding=“UTF-8”?> <!DOCTYPEhtmlPUBLIC“-//W3C//DTDXHTML1.0Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <htmlxmlns=“http://www.w3.org/1999/xhtml” xmlns:h=“http://xmlns.jcp.org/jsf/html“> <h:body> <h:form> <h:panelGridcolumns=“2”> <h:outputLabelfor=“name”value=“Name”/> <h:inputTextid=“name”value=”#{customer.name}”/> <h:outputLabelfor=“lastName”value=“Surname”/> <h:inputTextid=“surname”value=”#{customer.surname}”/> <h:panelGroup/> </h:panelGrid> </h:form> </h:body> </html> Note Bydefault,thenameofthebeanwillbetheclassnamewithitsfirstletterswitchedto lowercase;thus,theCustomerbeancanbereferredtoascustomer. Ifyouwanttouseadifferentnamingpolicyforyourbean,youcouldusethe@Named annotationasfollows: @Named(value=“customNamed”) Thisway,wewillbeabletoreferenceourCDIBeansusingtheidentifiedcustomNamed value. Insteadoftwo@RequestScopedand@Namedannotations,wecanjustusethe@Model annotationthataggregatesthem. CDIscopes CDIBeanscomewithasetofpredefinedscopesandannotations,andeachCDIBeanhas adistinctlifecycledeterminedbythescopeitbelongsto.Thefollowingtabledescribes thebuilt-inCDIscopesandannotationsrequiredtosetthesescopes: Scope Description @RequestScoped The@RequestScopedbeansaresharedduringthelengthofasinglerequest.ThiscouldbeanHTTPrequest,aremoteEJBinvocation,awebservicesinvocation,ormessagedeliveredtoa MessageDrivenBean(MDB).Thesebeansaredestroyedattheendoftherequest. @ConversationScoped The@ConversationScopedbeansaresharedacrossmultiplerequestsinthesameHTTPsessionbutonlyifthereisanactiveconversationmaintained.ConversationsaresupportedforJSF requeststhroughthejavax.enterprise.context.Conversationbean. @SessionScoped The@SessionScopedbeansaresharedbetweenalltherequeststhatoccurinthesameHTTPsessionanddestroyedwhenthesessionisdestroyed. @ApplicationScoped An@ApplicationScopedbeanwillliveforaslongastheapplicationisrunningandbedestroyedwhentheapplicationisshutdown. @Dependent The@Dependentbeansareneversharedbetweeninjectionpoints.Anyinjectionofadependentbeanisanewinstancewhoselifecycleisboundtothelifecycleoftheobjectitisbeing injectedinto. OtherpartsofJavaEEcanextendthelistofavailablescopes.InJavaEE7(intheJava TransactionAPIspecification),anewscopehasbeenintroduced:@TransactionScoped.It boundsthelifecycleofabeanwiththecurrenttransaction.Itisofcoursepossibleto introduceyourowncustomscopes. Inthischapterexample,wewillusetheRequestScopedandSessionScopedbeansto driveoursimpleticket-bookingsystem.Inthenextchapter,wewillfurtherenhanceour exampleusingConversationScopedbeans,whichareapeculiarscopeofCDIBeans. Providingadetailedexplanationofallthenamedbeansscopesisbeyondthescopeofthis book.However,youcanquenchyourthirstforknowledgebyhavingalookatCDI ReferenceImplementation(JBossWeld)docsat http://docs.jboss.org/weld/reference/latest/en-US/html/scopescontexts.html. WildFlyCDIimplementation WeldistheCDIReferenceImplementationthatoriginatedaspartoftheSeam3project (http://www.seamframework.org/).WeldprovidesacompleteCDIimplementation,which canbeapartofaJavaEE7containersuchasWildFly. Therefore,inordertorunCDI-basedapplicationsonWildFly,youdon’tneedtodownload anyextralibrariesasWeldispartoftheservermodules,anditisincludedinallserver configurationsasstatedbythefollowingextension: <extensionmodule=“org.jboss.as.weld”/> Havingyourmoduleinstalled,however,doesnotmeanthatyoucanblindlyuseitinyour applications.ThegeneralruleisthatonWildFly,everyapplicationmoduleisisolated fromothermodules;thismeans,bydefault,itdoesnothavevisibilityontheASmodules, nordotheASmoduleshavevisibilityontheapplication. Tobeaccurate,wecouldstatethatallWildFlymodulesfallintothefollowingthree categories: Modulesthatareimplicitlyaddedtoyourapplications:Thiscategoryincludesthe mostcommonAPIssuchasjavax.activation,javax.annotation, javax.security,javax.transaction,javax.jms,andjavax.xml.Usingthese modulesdoesnotrequireanyextraeffortasWildFlywilladdthemforyouifyouare referencingtheminyourapplication. Modulesthatareaddedonconditions:Thiscategoryincludesjavax.ejb, org.jboss.resteasyandorg.hibernate,org.jboss.as.web,andfinally org.jboss.as.weld.Allthesemoduleswillbeaddedontheconditionthatyou supplyitscoreannotations(suchas@StatelessforEJB)oritscoreconfiguration files,forexample,web.xmlforawebapplication. Modulesthatneedtobeexplicitlyenabledbytheapplicationdeployer:This includesallothermodules,suchasyourcustommodules,thatyoucanaddtothe applicationserver.Thesimplestwaytoallowyoutohavevisibilitytothesemodules isaddinganexplicitdependencytoyourMETA-INF/MANIFEST.MFfile.Forexample,if youwanttotriggerthelog4jdependency,youhavetocodeyourmanifestfileas follows: Dependencies:org.apache.log4j Thereisalsoacustomdescriptorfileavailable,whichisusedbyWildFlytoresolve dependencies–jboss-deployment-structure.xml.Itallowsthedevelopertoconfigure therequireddependenciesinafine-grainedmatter.Thefileisplacedinthetop-level deploymentfile,intheMETA-INFdirectory(orWEB-INFforawebarchive).Asample contentoftheXMLfile(alongwiththeXSDschema)isavailableat https://docs.jboss.org/author/display/WFLY8/Class+Loading+in+WildFly. So,ifyouhavefollowedourchecklistcarefully,youwillbeawarethatinordertolet WeldlibrarieskickinandautomaticallydiscoveryourCDIbeans,youshouldadditscore configurationfile,whichisbeans.xml.Thisfilecanbeplacedinyourapplicationatthe followinglocations: InyourWEB-INFfolderifyouaredevelopingawebapplication InyourMETA-INFfolderifyouaredeployingaJARarchive Thebeans.xmlfileisbasedonthefollowingschemareference: <beansxmlns=“http://xmlns.jcp.org/xml/ns/javaee” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd” version=“1.1”bean-discovery-mode=“all”> </beans> However,itisperfectlylegaltoplaceanemptybeans.xmlfileinthecorrectlocation;if youdoso,CDIwillbeenabledinyourapplication.Ifyou,however,donotplacea beans.xmlfile,thenonlyanannotatedsubsetofclasseswillbeconsideredasbeans.In suchacase,thecontainerwillcreatebeansonlyforclassesthatareannotatedwithCDIrelatedannotationsandignoretherest.Mostofthetimes,thisisnotthebehaviorwe expect,anditdiffersfromthedefaultmodeinJavaEE6(whenthebeans.xmlfilewas required). Youmighthavenoticedthatthebean-discovery-modeattributeissettoallinour beans.xmlfile.ThisallowsustoconfiguretheCDIdiscoverymodewediscussedinthe previousparagraph.Itstatesthateverylegibleclassinourarchivewillbetreatedasa managedbean.Youcanplacea@Vetoedannotationonaclasstofilteritoutfromthebean discoveryprocess.Itisalsopossibletosetthediscoverymodetoannotatedsothatyou canplaceascopeannotationforeveryclassthatyouwouldliketouseasabean.Thisis thedefaultvalueofthenewestCDIversion(alsowhenthereisnobeans.xml),sobesure tosetitonforalloursamples. Rethinkingyourticketingsystem OnceyouhavelearnedthebasicsofCDI,wewillstartre-engineeringtheticket-booking systemusingCDIBeanswherevernecessary.Wewillturnitintoaleanerapplicationby droppingafewitemssuchasremoteinterfacesorasynchronousmethods,whicharenot neededinthisexample.Bydoingthis,youwillbeabletofocusjustonthecomponents thatareactuallyusedinthewebapplication. Let’screateanewMavenproject,justaswedidinthepreviouschapter: 1. FromtheFilemenu,gotoNew|MavenProject;followthewizardaswedid previously(remembertochecktheCreateasimpleprojectoption). 2. Onthenextscreen,entercom.packtpub.wflydevelopment.chapter4asGroupId, ticket-agency-cdiasArtifactId,andsetpackagingtowar: 3. ClickonFinish.TheMavenpluginforEclipsewillgenerateaprojectstructurefor youthatyouknowfromthepreviouschapter. 4. Theonlydifferenceisthatbesidesthestandardjava(forJavaclasses)and resources(forconfigurationfiles)folders,anewdirectorynamedwebappthatwill hostthewebapplicationviews. Addingtherequireddependencies Inordertocompileandruntheproject,ourMaven’spom.xmlfilewillrequirethe followingsetofdependenciesknownfromthepreviouschapter: <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.1.4.GA</version> <scope>provided</scope> </dependency> </dependencies> Wewillalsorequiretwopluginsfromthepreviouschapter(notethatwechangedthe extensionofthefilenamefromjartowar): <build> <finalName>${project.artifactId}</finalName> <plugins> <!—WildFlyplugintodeploytheapplication—> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>1.0.2.Final</version> <configuration> <filename>${project.build.finalName}.war</filename> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <!—enforceJava8—> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> IncaseyouhaveanyproblemswiththePOMconfigurationfile,besurethatyoucheckthe sourcecodeattachedtothisbookandthematerialfromthepreviouschapter. Creatingthebeans Onceyourprojectisproperlyconfigured,wecanstartmodelingourbeans.Thefirstbean wewillupgradeisTheatreBooker,whichwilldrivetheusersession,accessingtheticket listfromourTheatreBoxbean: packagecom.packtpub.wflydevelopment.chapter4.controller; importcom.packtpub.wflydevelopment.chapter4.boundary.TheatreBox; importorg.jboss.logging.Logger; importjavax.annotation.PostConstruct; importjavax.enterprise.context.SessionScoped; importjavax.faces.application.FacesMessage; importjavax.faces.context.FacesContext; importjavax.inject.Inject; importjavax.inject.Named; importjava.io.Serializable; @Named[1] @SessionScoped[2] publicclassTheatreBookerimplementsSerializable{ @Inject privateLoggerlogger;[3] @Inject privateTheatreBoxtheatreBox;[4] @Inject privateFacesContextfacesContext;[5] privateintmoney; @PostConstruct publicvoidcreateCustomer(){ this.money=100; } publicvoidbookSeat(intseatId){ logger.info(“Bookingseat”+seatId); intseatPrice=theatreBox.getSeatPrice(seatId); if(seatPrice>money){ FacesMessagem=newFacesMessage(FacesMessage.SEVERITY_ERROR, “NotenoughMoney!”,“Registrationunsuccessful”);[6] facesContext.addMessage(null,m); return; } theatreBox.buyTicket(seatId); FacesMessagem=newFacesMessage(FacesMessage.SEVERITY_INFO, “Booked!”,“Bookingsuccessful”); facesContext.addMessage(null,m); logger.info(“Seatbooked.”); money=money-seatPrice; } publicintgetMoney(){ returnmoney; } } Asyoucansee,thebeanhasbeentaggedasNamed[1],whichmeansthatitcanbe directlyreferencedinourJSFpages.ThebeanisSessionScoped[2]sinceitstoresthe amountofmoneyavailabletothecustomerduringitssession. Wewouldalsoliketoinjectlogger[3]andFacesContextFacexContexts[5]insteadof manuallydefiningit.Todothis,wewillneedtoregisterabeanthatproducesloggers, whichareparameterizedwiththenameoftheclass.Wewillcoverthisprocessof producingbeansinamoment. Finally,noticethatwecansafelyinjectEJBsintoourCDIBeansusingtheInject[4] annotation.Also,thereverseisperfectlylegal,thatis,injectingCDIBeansintoEJBs. Comparedtoourearlierproject,herewedon’traiseJavaexceptionswhenthecustomeris notabletoaffordaticket.Sincetheapplicationiswebbased,wesimplydisplayawarning messagetotheclientusingJSFFacesMessages[6]. TheotherbeanthatwestilluseinourapplicationisTheatreInfo,whichhasbeenmoved tothecontrollerpackageasitwillactuallyprovidetheapplicationwiththelistof availableseats: packagecom.packtpub.wflydevelopment.chapter4.controller; importcom.google.common.collect.Lists; importcom.packtpub.wflydevelopment.chapter4.boundary.TheatreBox; importcom.packtpub.wflydevelopment.chapter4.entity.Seat; importjavax.annotation.PostConstruct; importjavax.enterprise.event.Observes; importjavax.enterprise.event.Reception; importjavax.enterprise.inject.Model; importjavax.enterprise.inject.Produces; importjavax.inject.Inject; importjavax.inject.Named; importjava.util.Collection; @Model[1] publicclassTheatreInfo{ @Inject privateTheatreBoxbox; privateCollection<Seat>seats; @PostConstruct publicvoidretrieveAllSeatsOrderedByName(){ seats=box.getSeats(); } @Produces[2] @Named publicCollection<Seat>getSeats(){ returnLists.newArrayList(seats); } publicvoidonMemberListChanged(@Observes(notifyObserver= Reception.IF_EXISTS)finalSeatmember){ retrieveAllSeatsOrderedByName();[3] } } Atfirst,havealookatthe@Modelannotation[1],whichisanalias(wecallthiskindof annotationsstereotypes)fortwocommonlyusedannotations:@Namedand @RequestScoped.Therefore,thisbeanwillbenamedintoourJSFpageandwillcarrya requestscope. Next,payattentiontothegetSeatsmethod.Thismethodreturnsalistofseats,exposing itasaproducermethod[2]. Note Theproducermethodallowsyoutohavecontrolovertheproductionofthedependency objects.AsaJavafactorypattern,theycanbeusedasasourceofobjectswhose implementationmayvaryatruntimeoriftheobjectrequiressomecustominitialization thatisnottobeperformedintheconstructor. Itcanbeusedtoprovideanykindofconcreteclassimplementation;however,itis especiallyusefultoinjectJavaEEresourcesintoyourapplication. Oneadvantageofusinga@ProducerannotationforthegetSeatsmethodisthatits objectscanbeexposeddirectlyviaJSF’sExpressionLanguage(EL),aswewillseeina minute. Finally,anotherfeatureofCDIthatwasunleashedinthisexampleistheobserver.An observer,asthenamesuggests,canbeusedtoobserveevents.Anobservermethodis notifiedwheneveranobjectiscreated,removed,orupdated.Inourexample,itallowsthe listofseatstoberefreshedwhenevertheyareneeded. Note Tobeprecise,inourexample,weareusingaconditionalobserverthatisdenotedbythe expressionnotifyObserver=Reception.IF_EXISTS.Thismeansthatinpractice,the observermethodisonlycalledifaninstanceofthecomponentalreadyexists.Ifnot specified,thedefaultoption(ALWAYS)willbethattheobservermethodisalwayscalled.(If aninstancedoesn’texist,itwillbecreated.) InthenewestCDIversion,itispossibletogetadditionalinformationaboutthefiredevent intheobserverbyaddinganEventMetadataparametertotheobserver’smethod. Wheneverachangeinourlistofseatsoccurs,wewillusethe javax.enterprise.event.Eventobjecttonotifytheobserveraboutthechanges.This willbedoneinoursingletonbean,whichgetsinjectedwiththeseat’sevent[1],and notifiestheobserverbyfiringtheeventwhenaseatisbooked[2]: packagecom.packtpub.wflydevelopment.chapter4.boundary; importjavax.enterprise.event.Event; @Singleton @Startup @AccessTimeout(value=5,unit=TimeUnit.MINUTES) publicclassTheatreBox{ @Inject[1] privateEvent<Seat>seatEvent; @Lock(WRITE) publicvoidbuyTicket(intseatId){ finalSeatseat=getSeat(seatId); finalSeatbookedSeat=seat.getBookedSeat(); addSeat(bookedSeat); seatEvent.fire(bookedSeat);[2] } //Restofthecodestaysthesame,asinthepreviouschapter } Earlier,wementionedthatapreconfiguredloggershouldbeinjectedtoabeanifit requestsit.Wewillcreateasimpleloggerproducerthatwillusetheinformationaboutthe injectionpoint(thebeanthatrequestsalogger)toconfigureaninstance: packagecom.packtpub.wflydevelopment.chapter4.util; importjavax.enterprise.inject.Produces; importjavax.enterprise.inject.spi.InjectionPoint; importorg.jboss.logging.Logger; publicclassLoggerProducer{ @Produces publicLoggerproduceLogger(InjectionPointinjectionPoint){ return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); } } WealsoallowedtheinjectionofFacesContextinsteadofusingthestandard FacesContext.getCurrentInstance()staticmethod.Thiscontextisused,forexample, todisplaythestatederrormessages: packagecom.packtpub.wflydevelopment.chapter4.util; importjavax.enterprise.context.RequestScoped; importjavax.enterprise.inject.Produces; importjavax.faces.context.FacesContext; publicclassFacesContextProducer{ @Produces @RequestScoped publicFacesContextproduceFacesContext(){ returnFacesContext.getCurrentInstance(); } } ThelastclasswewillincludeinourprojectistheSeatbean,knownfromtheprevious chapter,whichwillbeusedasourmodelwithoutanychange(remembertoincludeitin yourprojectwithaproperpackage). Buildingtheview Oncewehavecodedtheserversideofourexample,creatingthefrontendwillbequite easy,aswehavemadeallourresourcesavailablethroughCDIBeans. OnenotabledifferencebetweensomeoftheearliereditionsofthisbookisthatFacelets arenowthepreferredviewtechnologyforJSF.EarlierversionsofJSFusedJavaServer Pages(JSP)astheirdefaultviewtechnology.AsJSPtechnologypredatesJSF,usingJSP withJSFsometimesfeltunnaturalorcreatedproblems.Forexample,thelifecycleofJSPs isdifferentfromthelifecycleofJSF. Note Comparedtothesimplerrequest-responseparadigmonwhichtheJSPlifecycleisbased, theJSFlifecycleismuchmorecomplexsincethecoreofJSFistheMVCpattern,which hasseveralimplications.UseractionsinJSF-generatedviewstakeplaceinaclientthat doesnothaveapermanentconnectiontotheserver.Thedeliveryofuseractionsorpage eventsisdelayeduntilanewconnectionisestablished.TheJSFlifecyclemusthandlethis delaybetweeneventandeventprocessing.Also,theJSFlifecyclemustensurethatthe viewiscorrectbeforerenderingit,andalsothattheJSFsystemincludesaphaseto validateinputsandanothertoupdatethemodelonlyafteralltheinputspassvalidation. MostofthetimeFaceletsareusedtobuildJavaServerFacesviewsusingHTML-style templatesandcomponenttrees.TemplatingisausefulfeatureavailablewithFaceletsthat allowsyoutocreateapagethatwillactasthetemplatefortheotherpagesinan application(somethinglikeStrutsTiles).Theideaistoobtainportionsofreusablecode withoutrepeatingthesamecodeondifferentpages. Sohere’sthemainapplicationstructurethatcontainsatemplatepagenamed default.xhtmlthatisreferencedbyviewsinthetemplateattributeofthepage’s compositionelement.ThetemplatecontainstwomainHTMLdivelementsthatwillbe usedtocontainthemainapplicationpanel(content)andafooterdiv(footer),whichwill barelyoutputtheapplicationtitle. Inordertoaddthetemplateatfirst,addanewJSFpagetotheWEB-INF/templatesfolder ofyourapplicationandnameitdefault.xhtml: <?xmlversion=‘1.0’encoding=‘UTF-8’?> <!DOCTYPEhtmlPUBLIC“-//W3C//DTDXHTML1.0Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <htmlxmlns=“http://www.w3.org/1999/xhtml” xmlns:h=“http://xmlns.jcp.org/jsf/html” xmlns:ui=“http://xmlns.jcp.org/jsf/facelets”> <h:head> <metahttp-equiv=“Content-Type”content=“text/html;charset=utf-8”/> <h:outputStylesheetname=“style.css”/> </h:head> <h:body> <divid=“container”> <divid=“content”> <ui:insertname=“content”> [Templatecontentwillbeinsertedhere] </ui:insert> </div> <divid=“footer”> <p> <em>WildFlyDevelopmentTicketBookingexample.</em><br/> </p> </div> </div> </h:body> </html> Next,wewilladdthemainpageview,whichwillbeembeddedintoyourtemplate.For thispurpose,addaJSFpagenamedindex.xhtmltothewebappfolderofyourMaven project: <?xmlversion=“1.0”encoding=“UTF-8”?> <ui:compositionxmlns=“http://www.w3.org/1999/xhtml” xmlns:ui=“http://xmlns.jcp.org/jsf/facelets” xmlns:f=“http://xmlns.jcp.org/jsf/core” xmlns:h=“http://xmlns.jcp.org/jsf/html” template=”/WEB-INF/templates/default.xhtml”>[1] <ui:definename=“content”> <h1>TicketBookerMachine</h1> <h:formid=“reg”> <h3>Money:$#{theatreBooker.money}</h3>[2] <h:messageserrorClass=“error”infoClass=“info” globalOnly=“true”/> <h:panelGridcolumns=“1”border=“1”styleClass=“smoke”> <h:dataTablevar=“_seat”value=”#{seats}”[3] rendered=”#{notemptyseats}” styleClass=“simpletablestyle”> <h:column> <f:facetname=“header”>Id</f:facet> #{_seat.id} </h:column> <h:column> <f:facetname=“header”>Name</f:facet> #{_seat.name} </h:column> <h:column> <f:facetname=“header”>Price</f:facet> #{_seat.price}$ </h:column> <h:column> <f:facetname=“header”>Booked</f:facet> #{_seat.booked} </h:column> <h:column> <f:facetname=“header”>Action</f:facet> <h:commandButtonid=“book” action=”#{theatreBooker.bookSeat(_seat.id)}”[4] disabled=”#{_seat.booked}” value=”#{_seat.booked?‘Reserved’:‘Book’}”/> </h:column> </h:dataTable> </h:panelGrid> </h:form> </ui:define> </ui:composition> Theui:compositionelementisatemplatingtagthatwrapscontenttobeincludedin anotherFacelet.Specifically,itwillbeincludedinthedefault.xhtml[1]template. Thecreationoftheviewisdoneinthreesteps.First,wewilldisplaythecustomer’s money[2],whichisboundtothesessionvariablecalledmoney. Note NoticehowwedirectlyreferenceCDIBeans(forexample,TheatreBooker)fromJSF expressions,justasweusedtodowithJSFManagedBeans. ThenextthingonthechecklistisprintingallJSFmessages[3]thataremeanttobe producedbytheapplicationviathemessageselement. Themaintaskofthisviewistoproduceaviewofallticketsandlettheuserspurchase them.ThisisachievedbymeansofadataTableobject[3]thatcanbeusedtoproducea tabularlistofobjects,whicharegenerallystoredasjava.util.Listinyourbeans. PayattentiontothevalueattributeofthedataTableobject: <h:dataTablevar=“_seat”value=”#{seats}” rendered=”#{notemptyseats}”styleClass=“simpletablestyle”> Inthiscase,wedon’tdirectlyreferenceaCDIBean,butwereferenceanobjectthathas beenproducedbyaCDIBean.Tobeprecise,ithasbeenproducedbyTheatreInfothat, aswehaveseen,hasa@Producesand@Namedannotationonourlistofseats: privateList<Seat>seats; @Produces @Named publicList<Seat>getSeats(){ returnseats; } ThisdataTableobjectwillbedisplayedonlyifitcontainssomedatainit(asdictatedby thenotemptyseatsELexpression).InoneofthedataTablecolumns,wehaveadded commandButton[4]thatwillbeusedtobooktheseatdisplayedonthatrow.Noticeoneof theJSF2goodieshere,aswecallthebookSeatmethodofTheatreBookerpassingan argumentasoneparameter,whichistheseatIdfield. JSF2facetsuggestions ByenablingJSF2facetsonyourprojectconfiguration,youcanenjoysomeadditional benefitswhiledesigningyourviews. EnablingJSF2projectfacetstakeshalfaminute.Right-clickonyourprojectandnavigate toProperties|ProjectFacets.Then,selecttheJSF2.2Projectfacetscheckboxand clickontheOKbutton: Note OncetheJSFfacetisenabled,EclipsewillnotifyyouthattheJSFlibraryconfigurationis missing;justdisabletheJSFlibraryconfigurationthatisapartofMaven’sduty. OnceJSF2facetsareconfigured,ifyoupressCtrl+Spacebarbeforereferencingafield ormethod,asuggestionpop-upwindowwillletyouchoosethemethodorattributeofthe Beanyouwanttoreference. Gettingreadytoruntheapplication OK,nowyourapplicationisalmostready.WejustneedtoconfigureaJSFmappingina web.xmlfileasfollows: <web-appxmlns=“http://xmlns.jcp.org/xml/ns/javaee” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd” version=“3.1”> <servlet> <servlet-name>FacesServlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>FacesServlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>faces/index.xhtml</welcome-file> </welcome-file-list> </web-app> ThiswillthenruntheFacesServletservletforallthepagesat/faces/*url. Finally,asstatedpreviously,inordertoactivateourwarfileasanexplicitbeanarchive, weneedtoaddanemptybeans.xmlfiletotheWEB-INFfolderofyourapplication. So,ifyoufollowthesamenamingconventionusedinthischapter,youwillendupwith thefollowingprojectstructure: Atthispoint,youmustbefamiliarwithbuildinganddeployingyourMavenapplications usingEclipseorashell.Assumingthatyouaremanagingyourapplicationfromashell, startbybuildinguptheprojectusingthefollowing: mvnpackage Then,publishitusingtheWildFlyMavenplugin,aswedidinthepreviouschapter. IftheWildFlyserverisstarted,youcanexecutethefollowingcommand: mvnwildfly:deploy IftheWildFlyserverisnotstarted,youcanexecutethefollowingcommandandthenthe WildFlyMavenpluginwillautomaticallystartaninstance: mvnwildfly:run Theapplicationwillbeavailableathttp://localhost:8080/ticket-agency-cdi. Then,todothiswithauniquecommand,youcanexecutethefollowing: mvncleanpackagewildfly:deploy Aftersomuchwork,youwillbepleasedtohaveyourapplicationrunningonyour browser: Rightnow,youwillbeabletobookticketsuptothebudget($100)definedinyour SessionScopedbean.SoenjoythisfirsttasteofJSFandCDI. Ofcourse,inthischapter,weonlyscratchedthesurfaceofJSFfeatures.Thereisalsoa newhigher-levelapproachintroducedinJSF2.2thatcanbeusedforflow-basedscenarios suchasashoppingcart.ThenewfeatureiscalledFacesFlowandcomeswitha @FlowScopedannotation.However,wewillnowfocusonaddingsomeotherfeaturesto ourcurrentapplication. Combiningtheschedulerintoourapplication Uptonow,wehavenotincludedthescheduler,whichwasinchargeofsimulatingother customer-requestingtickets,intoourapplication.Thiswasnotanoversight;asamatterof fact,introducinganexternalsysteminawebapplicationposessomechallenges.For example,whatiftheschedulerupdatessomedatausedbytheapplication?Howwillthe userknowit? Thereareseveralstrategiestoaddressthisrequirement;however,theyallboildownto usingsomeintelligenceinyourclientapplication.Forexample,ifyouarefamiliarwith webscriptinglanguages,youcanusethepopularjQueryAPItopolltheserverforsome updates.ThenewestversionofJSF2.2comeswithgreatsupportforHTML5and JavaScriptframeworks,thankstothecustomdataattributesandpass-throughelements. ThesearesimplemechanismsthatallowtheJSF’srenderkittorenderpartsofthepage withoutanyfurtherchangessothatcustomtagsmaybeinterpretedbythebrowser(ora JavaScriptframework). SincenotallJavaEEdevelopersmightbeskilledinJavaScript,wewouldrathershowa simpleandeffectivewaytofulfillourrequirementusingRichFaceslibraries (http://www.jboss.org/richfaces),whichprovideadvancedAjaxsupportalongwitharich setofready-to-usecomponents. InstallingRichFaces InstallingRichFacesrequiresasetofcorelibrariesthataregenerallyavailableatthe RichFacesdownloadpage. Additionally,youneedtoprovideasetofthird-partydependenciesthatareusedbythe RichFacesAPI.Nevermind,that’swhatMavenisfor!StartbyaddingthelatestBillof Materials(BOM)fortheRichFacesAPIintheupperdependency-managementsection: <dependencyManagement> … <dependency> <groupId>org.richfaces</groupId> <artifactId>richfaces-bom</artifactId> <version>4.3.5.Final</version> <scope>import</scope> <type>pom</type> </dependencies> </dependencyManagement> Then,it’sjustamatterofaddingtherichUIlibrariesandthecoreAPI: <dependency> <groupId>org.richfaces.ui</groupId> <artifactId>richfaces-components-ui</artifactId> </dependency> <dependency> <groupId>org.richfaces.core</groupId> <artifactId>richfaces-core-impl</artifactId> </dependency> Makingyourapplicationrich OncewehaveinstalledRichFaceslibraries,wewilljustneedtoreferencethemoneach XHTMLpageinyourproject.Here’sthenewindex.xhtmlpageusingtheRichFaces namespaces: <ui:compositionxmlns=“http://www.w3.org/1999/xhtml” xmlns:h=“http://xmlns.jcp.org/jsf/html” xmlns:f=“http://xmlns.jcp.org/jsf/core” xmlns:ui=“http://xmlns.jcp.org/jsf/facelets” xmlns:a4j=“http://richfaces.org/a4j” xmlns:rich=“http://richfaces.org/rich” template=”/WEB-INF/templates/default.xhtml”> <ui:definename=“content”> <f:view> <h:form> <a4j:pollid=“poll”interval=“2000” enabled=”#{pollerBean.pollingActive}” render=“poll,grid,bookedCounter”/> <rich:panelheader=“TicketBookerMachine” style=“width:350px”> <h2>BookyourTicket</h2> <h3>Money:$#{theatreBooker.money}</h3> <h:messageserrorClass=“error”infoClass=“info” globalOnly=“true”/> <rich:dataTableid=“grid”var=“_seat” value=”#{seats}” rendered=”#{notemptyseats}” styleClass=“simpletablestyle”> <h:column> <f:facetname=“header”>Id</f:facet> #{_seat.id} </h:column> <h:column> <f:facetname=“header”>Name</f:facet> #{_seat.name} </h:column> <h:column> <f:facetname=“header”>Price</f:facet> #{_seat.price} </h:column> <h:column> <f:facetname=“header”>Booked</f:facet> #{_seat.booked} </h:column> <h:column> <f:facetname=“header”>Action</f:facet> <h:commandButtonid=“book” action=”#{theatreBooker.bookSeat(_seat.id)}” disabled=”#{_seat.booked}” value=”#{_seat.booked?‘NotAvailable’: ‘Book’}”/> </h:column> </rich:dataTable> <h:outputTextvalue=“Bookedseatsonthispage:# {bookingRecord.bookedCount}”id=“bookedCounter”/> </rich:panel> </h:form> </f:view> </ui:define> </ui:composition> Wehavehighlightedthecoreenhancementsaddedtothispage.Atfirst,aswesaid,we needtoreferencetheRichFaceslibrariesatthetopoftheXHTMLpage. Next,weaddedarichAjaxcomponent,a4j:poll,whichdoesasimplebutaneffectivejob ofpollingtheserverforupdates,allowingthere-renderingofourcomponents—grid (whichcontainsthemaindatatable),poller(tocheckwhetheritshouldstillberunning), andbookedCounter. Additionally,thiscomponentreferencesaCDIbeannamedPoller,whichactsjustasan on/offflagforourpoller.Weexpecttoturnoffpollingassoonasalltheseatsaresoldout: packagecom.packtpub.wflydevelopment.chapter4.controller; importjava.util.Optional; importjavax.enterprise.inject.Model; importjavax.inject.Inject; importcom.packtpub.wflydevelopment.chapter4.boundary.TheatreBox; importcom.packtpub.wflydevelopment.chapter4.entity.Seat; @Model publicclassPoller{ @Inject privateTheatreBoxtheatreBox; publicbooleanisPollingActive(){ returnareFreeSeatsAvailable(); } privatebooleanareFreeSeatsAvailable(){ finalOptional<Seat>firstSeat= theatreBox.getSeats().stream().filter(seat-> !seat.isBooked()).findFirst(); returnfirstSeat.isPresent(); } } Oursellerservicestaysnearlythesameasinthepreviouschapter(theonlydifferenceis theloggerinjection): packagecom.packtpub.wflydevelopment.chapter4.control; importcom.packtpub.wflydevelopment.chapter4.boundary.TheatreBox; importcom.packtpub.wflydevelopment.chapter4.entity.Seat; importorg.jboss.logging.Logger; importjavax.annotation.Resource; importjavax.ejb.EJB; importjavax.ejb.Schedule; importjavax.ejb.Stateless; importjavax.ejb.Timer; importjavax.ejb.TimerService; importjavax.inject.Inject; importjava.util.Collection; importjava.util.Optional; @Stateless publicclassAutomaticSellerService{ @Inject privateLoggerlogger; @Inject privateTheatreBoxtheatreBox; @Resource privateTimerServicetimerService; @Schedule(hour=“*”,minute=“*”,second=“*/30”,persistent= false) publicvoidautomaticCustomer(){ finalOptional<Seat>seatOptional=findFreeSeat(); if(!seatOptional.isPresent()){ cancelTimers(); logger.info(“Schedulergone!”); return;//Nomoreseats } finalSeatseat=seatOptional.get(); theatreBox.buyTicket(seat.getId()); logger.info(“Somebodyjustbookedseatnumber”+seat.getId()); } privateOptional<Seat>findFreeSeat(){ finalCollection<Seat>list=theatreBox.getSeats(); returnlist.stream().filter(seat->!seat.isBooked()).findFirst(); } privatevoidcancelTimers(){ for(Timertimer:timerService.getTimers()){ timer.cancel(); } } } Finally,we’lladdabookingrecord,whichwillbeboundedwiththecurrentviewusingthe viewscope.Itsrolewillbetocountthenumberofbookingsdonebytheuserinthe currentview(asinglebrowsertabisconsideredasingleview): packagecom.packtpub.wflydevelopment.chapter4.controller; importcom.packtpub.wflydevelopment.chapter4.entity.Seat; importjava.io.Serializable; importjavax.enterprise.event.Observes; importjavax.faces.view.ViewScoped; importjavax.inject.Named; @Named @ViewScoped publicclassBookingRecordimplementsSerializable{ privateintbookedCount=0; publicintgetBookedCount(){ returnbookedCount; } publicvoidbookEvent(@ObservesSeatbookedSeat){ bookedCount++; } } Youcanexperimentwiththebookedcounterbytryingtobookticketsviatwoseparate tabsinyourbrowser. Youmighthavenoticedthatweplacedtwoannotationsonthebean:@Namedand @ViewScoped.IfyouwouldliketodefinemultiplebeanswithaspecificsetofCDI annotations,itwouldbeagoodideatocreateyourowncustomannotationthatalready containsthedesiredones.Thiskindofconstructioniscalledastereotype.Itispossibleto incorporatethefollowingelements: Adefaultscope Optionally,interceptorbindings Optionally,a@Namedannotation Optionally,an@Alternativeannotation Tocreateastereotype,youneedtoaddthewantedannotationsalongwiththe @Stereotypeannotation: @ViewScoped @Named @Stereotype @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public@interfaceNamedView{ } NowyoucandefinetheBookinRecordbeanasfollows: @NamedView publicclassBookingRecordimplementsSerializable{ //Somecodehere } The@ModelstereotypeisavailableinCDIbydefault.Itdefinesarequestscopednamed bean,andyoucanuseitonyourbeansrightoutofthebox. Runningtheapplication Withallthelibrariesinplace,youcannowtestrunyournewrichapplication.Asyoucan see,every30secondsaticketissoldoutandbuttonsareturned,inrealtime,intoNot available: Creatinginterceptors ThereisonemoreCDIfeatureworthmentioninghere,theinterceptors.Sometimes, applicationscontainlogicandcross-cuttingmultiplelayers;themostsimpleexampleis logging.UndertheJavaEEplatform,itcanbeachievedusinginterceptors.First,weneed tocreateanewannotation: @Inherited @InterceptorBinding[1] @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD,ElementType.TYPE}) public@interfaceLogged{ //empty } Thisannotationdefinesaninterceptorbinding.Itcanbeusedtospecifymethodsthatyou wouldliketointercept.Thebindingscanbeusedontypesaswell;inthatcase,every methodcallonthattypeisintercepted.Themostimportantpartofthisdefinitionisthe @InterceptorBinding[1]annotation.Besuretoaddit! Then,wehavetocreatetheinterceptordefinitionitself: @Interceptor @Logged[1] publicclassLoggingInterceptorimplementsSerializable{ @AroundInvoke[2] publicObjectlog(InvocationContextcontext)throwsException{ finalLoggerlogger= Logger.getLogger(context.getTarget().getClass()); logger.infov(“Executingmethod{0}”, context.getMethod().toString()); returncontext.proceed()[3]; } } Westartbystatingthatourclassis@Interceptoranditwillbeusingtheinterceptor bindingthatwe’vedefinedearlier(@Logged[1]).Next,wecreateamethodlogthatwill beexecutedaroundeverymethodexecution(@AroundInvoke[2])onannotatedclasses. Insideofit,wewillcallthecontext.proceed()methodthatwillbasicallyforwardthe calltotheoriginalreceiver.Notethattheinterceptorcandecide(basedonsomesecurity logic,forinstance)whetherthecallshouldbedropped.Itcouldevenanalyzeorchange thereturnedvalue. Finally,wehavetoenableitinthebeans.xmlfilebyaddingthefollowingcode: <interceptors> <class>com.packtpub.wflydevelopment.chapter4.util.LoggingInterceptor</class> </interceptors> Now,let’smoveontojusttheannotatedclassesormethodsthatyouwanttologusingthe @Loggedannotation.Forinstance,refertothefollowing: @Named @SessionScoped @Logged publicclassTheatreBookerimplementsSerializable{ //Somecode } AllcallstotheTheatreBookerpublicmethodswillnowbeloggedintotheconsole: 21:02:11INFO[com.packtpub.wflydevelopment.chapter4 .controller.TheatreBooker$Proxy$_$$_WeldSubclass](defaulttask-8) Executingmethodpublicint com.packtpub.wflydevelopment.chapter4.controller.TheatreBooker.getMoney() Inthecaseofmultipleinterceptors,theorderinwhichtheyareexecutedisdeterminedby the@Interceptor.Priorityannotation.Interceptorswithlowestprioritieswillbecalled first.BesuretochecktheconstantsdefinedinthePriorityannotation.Yourown interceptor’sprioritiesshouldbebetweentheAPPLICATIONandLIBRARY_AFTERscope. TherearealsootherinterestingCDImechanismsthatwewillnotcoverinthisbook,but aredefinitelyworthexploring:decoratorsandalternatives.Decoratorsarebasically stronglytypedinterceptorsthatarefocusedonthebusinesslogicofyourapplication. Alternativescanbeusedtoprovidealternativeimplementationsforspecificbeans. AreEJBsandJSFManagedBeansobsolete? Attheendofthischapter,wewouldliketogiveourhonestopinionaboutacommon questionposedbydevelopers,thatis,howEJB,JSFManagedBeans,andCDIinteract andwheretheboundarybetweenthemlies.Arethereredundanciesbetweenthem?Itis indeedabitconfusingsincetherearenowmultiplecomponentmodelsavailableinJava EE. JSFManagedBeanshavebeen,foralongtime,theactualgluebetweentheapplication viewandthebusinessmethods.SinceRelease2.0ofJSF,youcandeclareJSFManaged Beansviaanannotation,andthescopesareexpandedwithaviewscopeandtheabilityto createcustomscopes.However,thereisverylittlestillgoingonforJSFManagedBeans. MostofitsfeaturescanbereplacedbyCDIBeansthataremuchmoreflexibleandallow youtohaveabetterintegrationwithotherJavaEEcomponents.Eventheviewscope,in thenewestversionofJSF,hasbeenimplementedasaCDIcustomscope (javax.faces.view.ViewScoped),whichreplacestheoldjavax.faces.bean.ViewScoped (noticethenameofthepackage;it’sacommonmistaketomixthemup). Ontheotherhand,EJBs,eventhoughtheyusealessflexibleinjectionmechanism,still maintainsomeuniquefeaturessuchasschedulabletimers,asynchronousoperations,and poolingthatareessentialforthrottlingandassuringthattheapplicationprovidesagood qualityofservice.BeginningfromJavaEE7,EJBsnolongeraretheonlycomponents thathaveatransactionalnature.Thenew@Transactionalannotationallowsyoutouse declarativetransactionsinCDIbeansbysimplyplacingitonselectedmethods. Despitethis,it’slikelythatEJBsarenotdisappearingfromourcode,ratheritislikely (anddesirabletoo)thattheywillcontinuetobeusedforsomeoftheiruniquefeatures.For theremainingpartthough,itsfunctionalitywillbeexposedviaCDIinsteadofEJBs’own annotationssuchas@Statelessand@EJB. Summary Inthischapter,weprovidedanintroductiontoCDI.WecoveredhowJSFpagescan accessCDI-namedbeansasiftheywereJSFManagedBeans.WealsocoveredhowCDI makesiteasytoinjectdependenciesintoourcodeviathe@Injectannotation. Additionally,weexplainedhowwecanaddanotherlibraryoftheJBossecosystem (RichFaces)uncoveringjustoneaspectofitspotentiality. Untilnow,wehaveworkedwithin-memorydata,soit’stimetointroducestorageforour CDIapplicationsusingtheJavaPersistenceAPI,whichisthethemeofthenextchapter. Chapter5.CombiningPersistencewithCDI Intheearlierchapters,wediscussedJavaEE,combiningseveraltechnologiessuchas CDI.Theexamplessofar,however,arebasedonafalseassumptionthatallthe informationcanbestoredinmemory.Inthischapter,wewillshowhowtouseapersistent datastoreforourapplicationintheformofastandardrelationaldatabase. TheEnterpriseJavaBeans(EJB)3.2specificationincludesareferencetoapersistence specificationcalledtheJavaPersistenceAPI(JPA).ItisanAPItocreate,remove,and queryJavaobjectscalledentitiesthatcanbeusedwithinbothacompliantEJB3.x containerandastandardJavaSEenvironment.InJavaEE7,ithasbeenupdatedto Version2.1.YoucancheckoutthecurrentversionofthespecificationItheJSR338at https://jcp.org/en/jsr/detail?id=338. Weneedtowarnyouthatinthischapter,youhavealotofthingstolearnandhence conceptswillbecomingatyoufromeverydirection.However,attheendofit,youwillbe abletoappreciateexactlyhowtocreateanddeployacompleteJavaEE7application. Specifically,wewillcoverthefollowingtopics: ThekeyfeaturesofJPA Howtocreateyourentitiesanddatabaseschema HowtomanipulatetheentitiesusingCDIBeansandEJBs DeliveringafrontendtierforourapplicationusingJSFandFaceletstechnology Datapersistencemeetsthestandard ThearrivalofanEnterpriseJavaPersistencestandardbasedonthePlainOldJava Object(POJO)developmentmodelfillsasubstantialgapintheJavaEEplatform.The previousattempt(theEJB2.xspecification)missedthemarkandcreatedastereotypeof EJBentitybeansthatwasawkwardtodevelopandtooheavyformanyapplications. Therefore,itneverachievedwidespreadadoptionorgeneralapprovalinmanysectorsof theindustry. Softwaredevelopersknewwhattheywanted,butmanycouldnotfinditintheexisting standards,sotheydecidedtolookelsewhere.Whattheyfoundwaslightweightpersistence frameworks,bothinthecommercialandopensourcedomains. IncontrasttoEJB2.xentitybeans,theEJB3.0JavaPersistenceAPI(JPA)isametadata drivenPOJOtechnology,thatis,tosavethedataheldinJavaobjectsinadatabase,our objectsarenotrequiredtoimplementaninterface,extendaclass,orfitintoaframework pattern. AnotherkeyfeatureofJPAisthequerylanguagecalledtheJavaPersistenceQuery Language(JPQL),whichgivesyouawaytodefinethequeriesinaportableway, independentoftheparticulardatabaseyouuseinanenterpriseenvironment.JPAqueries resembleSQLqueriesbysyntaxbutoperateagainstentityobjectsratherthandirectlywith databasetables. WorkingwithJPA InspiredbyORMframeworkssuchasHibernate,JPAusesannotationstomapobjectstoa relationaldatabase.JPAentitiesarePOJOsthatdonotextendanyclassnorimplementany interface.Youdon’tevenneedXMLdescriptorsforyourmapping.Actually,theJPAAPI ismadeupofannotationsandonlyafewclassesandinterfaces.Forexample,wewill marktheCompanyclassas@Entity,shownasfollows: importjavax.persistence.Entity; importjavax.persistence.Id; @Entity publicclassCompany{ //Somecode @Id privateStringcompanyName; publicCompany(){} //Somecode } Theprecedingpieceofcodeshowstheminimalrequirementsforaclasstobepersistent, whichareasfollows: Itmustbeidentifiedasanentityusingthe@javax.persistence.Entityannotation Itmusthaveanidentifierattributeannotatedwith@javax.persistence.Id Itmusthaveano-argumentconstructorinatleasttheprotectedscope Sinceyouwilllearnbetterwithanexample,wewillshowhowtocreateanddeploya sampleJPAapplicationinWildFlyinthenextsection. Addingpersistencetoourapplication Inordertopersistdata,JPAneedsarelationaldatabase;wewillusethePostgreSQL database,whichisprettypopularamongdevelopersandcanbedownloadedforfreefrom http://www.postgresql.org/download/.Itisrecommendedtodownloadthelateststable releaseofPostgreSQL9.xandinstallitusingthesimpleinstallationwizard.Ifyoudon’t needafull-blowndatabase,thenkeepinmindthatlaterwewillalsoshowyouhowtouse anin-memorydatabaseprovidedbyWildFly,whichcanbeareallyusefulalternative duringdevelopment. Settingupthedatabase Wewillcreateadatabasenamedticketsystem;wewillthenaddausernamedjbossand assignhim/herallprivilegesontheschemas. OpenashellunderthebinfolderofyourPostgreSQLinstallationandlaunchthe executablepsql–Upostgres.Onceloggedinwiththepasswordfromyourinstallation, executethefollowingcommands: CREATEDATABASEticketsystem; CREATEUSERjbossWITHPASSWORD‘jboss’; GRANTALLPRIVILEGESONDATABASEticketsystemTOjboss; Oursimpleschemawillbemadeupoftwotables:theSEATtable,whichcontainsthelist ofalltheavailableseatsinthetheatre,andtheSEAT_TYPEtable,whichisusedto categorizetheseattypes.Thetwotablesareina1-nrelationshipandtheSEATtablehosts aforeignkeythatrelatestotheIDoftheSEAT_TYPEtable.Wewill,however,letJPA generatetheschemaforus,basedonourclasshierarchy,whichwewillmodelina moment. InstallingtheJDBCdriverinWildFly DatabaseconnectivityiscarriedoutinJavausingJDBCdrivers,whichareusedeither directlyinyourapplicationsorbehindthescenesinJPA.ThePostgreSQLJDBCdriver canbedownloadedforfreefromhttp://jdbc.postgresql.org/download.html. Oncethedownloadiscomplete,placethepostgresql-9.X-X.jdbc41.jarfileata convenientlocationonyourfilesystem.WewillnowseehowtoinstalltheJDBCdriverin WildFly. InJBossAS5and6,youusedtoinstalltheJDBCdriverinthecommon/libfolderofyour serverdistribution.Inthenewmodularserverarchitecture(introducedinJBossAS7),you havemorethanoneoptiontoinstallyourJDBCdriver.Therecommendedapproach consistsofinstallingthedriverasamodule. Theproceduretoinstallanewmodulerequirescreatingamodulepathunder JBOSS_HOME/modulesandplacingthe.jarlibrariesandthemodule.xmlfile(thatdeclares themodulenameanditsdependencies)there. Inourexample,wewilladdthefollowingunitstoourfilesystem: JBOSS_HOME/modules/org/postgresql/main/postgresql-9.3-1101.jdbc41.jar JBOSS_HOME/modules/org/postgresql/main/module.xml StartbysimplycreatingtherequireddirectoriesinyourWildFlyinstallation(towhichthe JBOSS_HOMEvariablepoints),andcopyingthedownloadedJARfiletothem. Now,inthemainfolder,addafilenamedmodule.xml.Thisfilecontainstheactual moduledefinition;themostinterestingpartofitisthemodulename(org.postgresql), whichcorrespondstothemoduleattributedefinedinyourdatasource. Next,youneedtostatethepathtotheJDBCdriverresourceandthemodule dependencies,asfollows: <modulexmlns=“urn:jboss:module:1.1”name=“org.postgresql”> <resources> <resource-rootpath=“postgresql-9.3-1101.jdbc41.jar“/> </resources> <dependencies> <modulename=“javax.api”/> <modulename=“javax.transaction.api”/> </dependencies> </module> Wearedonewiththemoduleinstallation.Nowweneedtodefineadatasourceinour configurationthatwillusethismoduleandholdapoolofconnectionsinourPostgreSQL database.Inordertodothis,youcaneditstandalone.xml/domain.xml,addingadriver elementtothedatasource’ssubsystem(besuretomergethisconfigurationwithany existingdatasourcesinyourconfiguration): <subsystemxmlns=“urn:jboss:domain:datasources:1.0”> <datasources> <datasourcejta=“false” jndi-name=“java:jboss/datasources/wflydevelopment” pool-name=“wflydevelopment”enabled=“true”> <connection-url> jdbc:postgresql://localhost:5432/ticketsystem </connection-url> <driver-class>org.postgresql.Driver</driver-class> <driver>postgresql</driver> <security> <user-name>jboss</user-name> <password>jboss</password> </security> </datasource> <drivers> <drivername=“postgresql”module=“org.postgresql”/> </drivers> </datasources> </subsystem> Asyoucansee,thenewconfigurationfileborrowsthesameXMLschemadefinitionfrom theearlierJBossASconfigurations,soitshouldnotbedifficulttomigratetothenew schema.Basically,youwilldefinetheconnectionpathtothedatabaseusingthe connection-urlstringandtheJDBCdriverclasswiththedriversection. Note SinceJBossAS7.1.0,it’smandatorythatthedatasourcebeboundtothejava:/or java:jboss/JNDInamespace.Thiswillstandardizetheresourcesdefinitionamong developers,avoidingbizarreJNDIbindings. Usingthecommand-lineinterfacetocreateanewdatasource Theapplicationserverprovidesmorethanoneoptiontoaddadatasourcetoyour configuration.Wewilljustmentionthecommand-lineinterfaceapproach,whichcanbe quiteuseful,especiallyifyouplantomodifyyourconfigurationusingscriptfiles. Launchthejboss-cli.shscript(orjboss-cli.bat)andconnecttotheapplicationserver, asfollows: [disconnected/]connect [standalone@localhost:9990/] Nowissuethefollowingcommand,whichactuallycreatesanewdatasource, accomplishingthesamegoalweobtainedbyeditingtheconfigurationfile: /subsystem=datasources/data-source=wflydevelopment:add(jndiname=java:jboss/datasources/wflydevelopment,driver-name=postgresql, connection-url=jdbc:postgresql://localhost:5432/ticketsystem,username=“jboss”,password=“jboss”) TheCLIshouldrespondwithasuccessmessageifeverythinggoeswell. CreatingtheMavenproject Theapplicationthatwe’regoingtocreateinthischapterwillrequireonlystandardJava EE7APIsfromus.Havingknowledgefrompreviouschapters,youshouldbeabletoset upaprojectforthischapterbyyourself!JustuseyourfavoriteIDEandcreateaMaven projectwithwartype.RemembertoincludetheconfigurationforJavaSE8,beans.xml andfaces-config.xmlfiles.Ifyoufaceanyproblems,rememberthatcodesamples availablewiththisbookcontainafullprojectbasedonthisexample. AddingtheMavenconfiguration NowthatyourMavenskeletonissetup,wewillincludetherequireddependenciessothat Eclipsewillbeabletocompileyourclassesasyoucodethem.Theonlydependencyyou willneedforthistypeisjavaee-api: <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> Cookingentities Nowthatwe’redonewiththeconfigurationpart,wewilladdourentitiestotheproject. Somevaluableoptionsexisttoautogenerateourentities,startingwiththedatabase schema.Forexample,theEclipse’sFilemenuincludesanoptionJPAEntitiesfrom Tablethat(onceaconnectionhasbeensetupinthedatabase)allowsyoutoreverseyour DBschema(orapartofit)intoJavaentities. Ifyouarewillingtotrythisoption,rememberthatyouneedtoactivatetheEclipseJPA facetinyourproject,fromProjectProperties,asshowninthefollowingscreenshot: OnemoreoptionismentionedinAppendix,RapidDevelopmentUsingJBossForge, whichdiscussesJBossForge,apowerful,rapidapplicationdevelopment(aimedatJava EE)andprojectcomprehensiontool. Inthischapter,wewillfocusongeneratingSQLscriptsfromJavaclasses.Whateveryour strategyis,theexpectedoutcomeneedstoconformtothefollowingentities.Hereisthe firstone,SeatType,whichmapsthetableSEAT_TYPE: @Entity[1] @Table(name=“seat_type”)[2] publicclassSeatTypeimplementsSerializable{ @Id[3] @GeneratedValue(strategy=GenerationType.IDENTITY) privateLongid; privateStringdescription; privateintprice; privateintquantity; //bi-directionalmany-to-oneassociationtoSeat @OneToMany(mappedBy=“seatType”,fetch=FetchType.EAGER)[4] privateList<Seat>seats; //GettersandSettersomittedforbrevity } Thefirstmeaningfulannotationis@Entity[1],whichdeclarestheclassEntity.The @Table[2]annotationisusedtomapthebeanclasswithadatabasetable. The@Idannotation,[3],isamandatoryone;itdescribestheprimarykeyofthetable. Alongwith@Id,[email protected] databaseisinchargeofgeneratingthevalue.YoucanchecktheJavadocofthisclassto exploreotherstrategiesforvaluegeneration. Movingalong,the@OneToManyannotation[4]definesanassociationwithone-to-many cardinality.Actually,theSeatTypeclasshasmanyseats.ThecorrespondingSeat referenceiscontainedinalistcollection.WedefinethemappedByattributeinordertoset thefield,whichownstherelationshiponthemanyside. ThefetchattributedefinesthatJPAshouldfetchthelistofseatswheneveraseattypeis loadedfromthedatabase.Alazyconfigurationforarelationshipwouldcausethelisttobe fetchedonthefirstcalltothatfield. Finally,notethatwehavenotincludedhere,forthesakeofbrevity,thefieldgettersand settersthathavebeengenerated. Let’stakealookattheSeatentity: @Entity publicclassSeatimplementsSerializable{ privatestaticfinallongserialVersionUID=89897231L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) privateLongid; privatebooleanbooked; //bi-directionalmany-to-oneassociationtoSeatType @ManyToOne[1] @JoinColumn(name=“seat_id”)[2] privateSeatTypeseatType; //GettersandSettersomittedforbrevity } Asyoucansee,theSeatentityhasthecorresponding@ManyToOne[1]annotation,which [email protected]@JoinColumn[2]notifiesthe JPAenginethattheseatTypefieldismappedthroughtheforeignkeyofthedatabase’s seatID. AddingBeanValidation BeanValidation(JSR-303)isavalidationmodelavailableaspartoftheJavaEE6 platform.Thenew1.1version(JSR-349)isapartofJavaEE7.TheBeanValidation modelissupportedbyconstraintsintheformofannotationsplacedonafield,method,or classofaJavaBeanscomponent,suchasamanagedbean. Inourexample,theSeatTypeentitywillbecreatedusinganinputform;therefore,wewill needtovalidatethedatathathasbeenenteredbytheuser. Inourexample,[email protected] everyfieldthatispartoftheSeatTypeentryform,andamorecomplexconstraintinthe descriptionfield,whichwillsetthemaximumsizefortheseatdescriptionto25(the @javax.validation.constraints.Sizeconstraint)andallowjustlettersandspacesinit ([email protected]): @Entity @Table(name=“seat_type) publicclassSeatTypeimplementsSerializable{ privatestaticfinallongserialVersionUID=3643635L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) privateLongid; @NotNull @Size(min=1,max=25,message=“YouneedtoenteraSeat Description(max25char)”) @Pattern(regexp=“[A-Za-z]*”,message=“Descriptionmustcontain onlylettersandspaces”) privateStringdescription; @NotNull privateIntegerprice; @NotNull privateIntegerquantity; privateSeatPositionposition; //Getters/Settershere } Asyoucansee,wecanalsoplaceadescriptiononaconstraint,whichcanbeusedto provideacustomizederrormessagetotheJSFlayershouldthedatafailtopassthe constraint.YoucanchecktheOracledocumentationforafulllistofconstraintsavailable athttp://docs.oracle.com/javaee/7/tutorial/doc/bean-validation001.htm#GIRCZ. Wealsohaveaddedaseatpositioninformationtoourseattype.Itisasimpleenum: publicenumSeatPosition{ ORCHESTRA(“Orchestra”,“orchestra”),BOX(“Box”,“box”), BALCONY(“Balcony”,“balcony”); privatefinalStringlabel; privatefinalStringdbRepresentation; privateSeatPosition(Stringlabel,StringdbRepresentation){ this.label=label; this.dbRepresentation=dbRepresentation; } publicStringgetDatabaseRepresentation(){ returndbRepresentation; } publicStringgetLabel(){ returnlabel; } } WhenwesaveourSeatTypeentityinthedatabase,wewillalsostoretheenumvaluewith it.EarlierversionsofJPAgaveustwooptionstoaddressitautomatically(besides manuallymanagingtheirstatus),@Enumarated(EnumType.STRING)and @Enumarated(EnumType.ORDINAL);bothhadtheirflaws.Thefirstoneissensitivetowards enumrenaming;theentitiesinthedatabasewillhavethefullnameoftheenumstored (whichsometimesisalsoawasteofthestoragespace).Thesecondonecouldcreate problemswhentheorderofenumswouldbechanged(becauseitstoredtheindexofthe enumvalue).FromJPA2.1,wecancreateaconverter,whichwillautomaticallyconvert ourenumattributestospecificentriesinthedatabase.Weonlyneedtocreateanannotated class,whichimplementstheAttributeConverterinterface: importjavax.persistence.AttributeConverter; importjavax.persistence.Converter; @Converter(autoApply=true) publicclassSeatPositionConverterimplements AttributeConverter<SeatPosition,String>{ @Override publicStringconvertToDatabaseColumn(SeatPositionattribute){ returnattribute.getDatabaseRepresentation(); } @Override publicSeatPositionconvertToEntityAttribute(StringdbData){ for(SeatPositionseatPosition:SeatPosition.values()){ if(dbData.equals(seatPosition.getDatabaseRepresentation())){ returnseatPosition; } } thrownewIllegalArgumentException(“Unknownattributevalue”+ dbData); } } That’sall,noadditionalconfigurationisrequired.TheautoApplyattributesettotrue signalsJPAtotakecareofallofourSeatPositionenumsinentities. Configuringpersistence TheEntityAPIlooksgreatandisveryintuitive,buthowdoestheserverknowwhich databaseissupposedtostore/querytheentityobjects?Thepersistence.xmlfile,which willbeplacedundersrc/main/resources/META-INFofyourproject,isthestandardJPA configurationfile.Byconfiguringthisfile,youcaneasilyswitchfromonepersistence providertoanotherandthus,alsofromoneapplicationservertoanother(believeitornot, thisisahugeleaptowardsapplicationservercompatibility). Inthepersistence.xmlfile,wewillbasicallyneedtospecifythepersistenceprovider andtheunderlyingdatasourceused.Simplycreatethefollowingfileunder src/main/resources/persistence.xml: <?xmlversion=“1.0”encoding=“UTF-8”?> <persistencexmlns=“http://xmlns.jcp.org/xml/ns/persistence” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd” version=“2.1”> <persistence-unitname=“primary”> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <class>com.packtpub.wflydevelopment.chapter5.entity.Seat</class> <class>com.packtpub.wflydevelopment.chapter5.entity.SeatType</class> <properties> <propertyname=“javax.persistence.schemageneration.database.action”value=“drop-and-create”/> </properties> </persistence-unit> </persistence> Wehavehighlightedthemostimportantattributesinpersistence.xml.Thenameattribute isamandatoryelement,whichwillbeusedtoreferencethepersistenceunitfromour EnterpriseJavaBeans. Intheexamplecode,weusetheWildFlybuilt-inmemoryH2database (http://www.h2database.com/)availablebydefaultat java:jboss/datasources/ExampleDS(sothatitispossibletoruntheexamplewithout anysetup).However,youcanuseaconfiguredPostgreSQLconnectionhere, java:jboss/datasources/wflydevelopment,whichwecreatedearlier.InJavaEE7,you couldevenomitthewholejta-data-sourcetag.Everycontainerisnowobligedto provideadefaultdatasourceforapplicationstouse.ForWildFly,itwouldbethe aforementionedH2database. Wealsodefinetheclassesthatshouldbeconsideredasentities.Thisisanoptionalstep;if theentitiesareinthesamearchiveasthepersistence.xmlfile,theywillbe autodiscovered. InpreviousJPAversions,almosteveryconfigurationneededsomeprovider-specific properties.InJPA2.1,anumberofstandardpropertieswereadded,suchaspresented javax.persistence.schema-generation.database.action.Thedrop-and-create valuecanbeusedtocreateanddropyourdatabasetableseachtimeyoudeployyour application.Thiscanbeanadvantageifyouwanttostartwithacleanstorageeachtime youdeploytheapplication. However,itisalsopossibletoinstructJPAtogenerateSQLscriptsforyou,soyoucan manuallyapplythemtothedatabase.Simplyaddthefollowingentriestoyour persistence-unittag: <propertyname=“javax.persistence.schema-generation-target” value=“scripts”/> <propertyname=“javax.persistence.ddl-create-script-target” value=“createSeats.sql”/> <propertyname=“javax.persistence.ddl-drop-script-target” value=“dropSeats.sql”/> Ifyoudon’tspecifythelocationbyspecifyinganadditionalproperty,thenthegenerated scriptswillbeplacedintheJBOSS_HOME/bindirectory,withthenamesthatyouprovided intheconfiguration.Thenamescanbeabsolutepaths,soyoucangetthescriptstoany placeinyourfilesystem(ifWildFlyispermittedtowritethemthereofcourse). Addingproducerclasses Producerclasseshavebeenintroducedintheearlierchapterasameansofprovidingsome resourcesthroughCDItoourapplication.Inthisexample,wewilluseittoproducemany resources,suchastheJPAEntityManagerandthelistofobjectsthataretransferredtothe JSFviews.Forthisreason,weprovidedtheLoggerProducer,FacesContextProducer, andEntityManagerProducerclassesthatcontainsomegeneral-purposeresourcesand singleinstancesoftheSeatProducerandSeatTypeProducerclasses,whichwillbeused toproducecollectionsofentities. Here’sthecontentofthethreebasicproducerclasses: publicclassLoggerProducer{ @Produces publicLoggerproduceLoger(InjectionPointinjectionPoint){ return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); } } publicclassFacesContextProducer{ @Produces @RequestScoped publicFacesContextproduceFacesContext(){ returnFacesContext.getCurrentInstance(); } } publicclassEntityManagerProducer{ @Produces @PersistenceContext privateEntityManagerem; } Asyoucansee,theseclasseswillbethefactoryforthefollowingthreekindsofresources: EntityManager:Thiswillresolvetheprimarypersistenceunitsincethereisjustone persistenceunitdefined java.util.Logger:Thiswilltracesomeinformationontheserverconsole FacesContext:ThiswillbeusedtooutputsomeJSFmessagesonthescreen Tip ProducersversustheJavaEE5@Resourceinjection Ifyouhaveneverusedthedependencyinjectionsframeworkbefore,youmightwonder whatthebenefitofaddinganextralayertoproducesomecontainerresourcesis.The reasonbecomesevidentonceyouneedtochangesomeconfigurationelements,suchas thepersistenceunit.WiththeolderJavaEE5approach,youwillbeforcedtochangethe @Resourceinjection’sdetailswherevertheyareused;however,usingaproducermethod foritwillcentralizeresourcecreation,makingchangestrivial. Next,wewilladdsomeentityproducers;let’saddtheSeatTypeProducerand SeatProducerclasses: @javax.enterprise.context.RequestScoped publicclassSeatTypeProducer{ @Inject privateSeatTypeDaoseatTypeDao; privateList<SeatType>seatTypes; @PostConstruct publicvoidretrieveAllSeatTypes(){ seatTypes=seatTypeDao.findAll(); } @Produces @Named publicList<SeatType>getSeatTypes(){ returnseatTypes; } publicvoidonListChanged(@Observes(notifyObserver= Reception.IF_EXISTS)finalSeatTypemember){ retrieveAllSeatTypes(); } } IfyouhavegonethroughourexampleinChapter4,LearningContextandDependency Injection,youwillfindnothingnewhere;asyoucansee,theclasswillmerelyproducea collectionofseatTypes,whichistaggedas@NamedsothattheycanbeaccessedfromJSF ELaswell.Additionally,theclasscontainsanobserverhandlermethod (onListChanged),whichwillbefiredwhendatainthecollectionischanged. ThecollectiondataisfilledusingtheretrieveAllSeatTypesmethod(loadedthefirstand onlytimewhentheclassisconstructed)oftheSeatTypeDaoCDIBean.Wewilldefine thisbeaninamoment;rightnow,wewilladdthelastproducerclassusedinthisexample, theSeatProducerbean: @javax.enterprise.context.RequestScoped publicclassSeatProducerimplementsSerializable{ @Inject privateSeatDaoseatDao; privateList<Seat>seats; @PostConstruct publicvoidretrieveAllSeats(){ seats=seatDao.findAllSeats(); } @Produces @Named publicList<Seat>getSeats(){ returnseats; } publicvoidonMemberListChanged(@Observes(notifyObserver= Reception.IF_EXISTS)finalSeatmember){ retrieveAllSeats(); } } TheprecedingbeanwillbeusedtoproducethelistofSeatobjectsthatwillactuallybe availableforbooking. Codingqueriesforyourapplication Asyoucanseefromtheearliercode,theproducerclassesmakeuseofbeansnamed SeatDaoandSeatTypeDaotofilltheircollectionsofdata.Thesebeansperformsome simplefindsontheSeatandSeatTypeobjects,asshowninthefollowingcode: @Stateless publicclassSeatDaoextendsAbstractDao<Seat>{ publicSeatDao(){ super(Seat.class); } } @Stateless publicclassSeatTypeDaoextendsAbstractDao<SeatType>{ publicSeatTypeDao(){ super(SeatType.class); } } @TransactionAttribute(TransactionAttributeType.REQUIRED) publicabstractclassAbstractDao<TextendsSerializable>implements Serializable{ privatefinalClass<T>clazz; @Inject privateEntityManagerem; publicAbstractDao(Class<T>clazz){ this.clazz=clazz; } publicTfind(Objectid){ returnem.find(clazz,id); } publicvoidpersist(finalTentity){ em.persist(entity); } publicList<T>findAll(){ finalCriteriaQuery<T>criteriaQuery= em.getCriteriaBuilder().createQuery(clazz); criteriaQuery.select(criteriaQuery.from(clazz)); returnem.createQuery(criteriaQuery).getResultList(); } publicvoiddeleteAll(){ finalCriteriaDelete<T>criteriaDelete= em.getCriteriaBuilder().createCriteriaDelete(clazz); criteriaDelete.from(clazz); em.createQuery(criteriaDelete).executeUpdate(); } } Asyoucansee,bothSeatDaoandSeatTypeDaobeansextendthegenericAbstractDao class.ItwrapsEntityManagerandprovidesbasictype-safeCRUDoperationssuchas findAll,persist,andsoonusingtheJPACriteriaAPI.JPAallowsexecutionofthe followingthreetypesofqueries: NativeSQL:ThesequeriesusethestandardSQLlanguage.Whenusingthistypeof queries,youhavetorememberqueriescanbeincompatiblewhenmigratingbetween differentdatabases. JavaPersistenceQueryLanguage(JPQL):Thesequeriescanbeformedusing speciallanguagesimilartoSQL.Inpractice,thismethodisoftenhardtomaintain withoutgoodIDEsupport,especiallyduringrefactoring.Thesequeriescanalsobe compiledatstartup,whichmeansthattheyarenotresolvedmultipletimes.Finally, theycanbeusedbyacachingmechanismtoavoidunnecessarydatabaseoperations forqueriesthatarecalledfrequently.Youcandefineaqueryanditsnameinthe entityinthe@NamedQuery(name=”…”,query=”…”)annotation. CriteriaAPI:ThesequeriescanbeformedbysimplyexecutingJavamethodsand theusageofappropriateobjects.SinceJPA2.1,it’spossibletoperformbulkupdates anddeletionsthroughthisAPI. Let’smakeasimplecomparisonofthesethreemethodsusinganexample.Wewanttojust getalltheobjectsofagiventype.UsingnativeSQL,thisquerywouldlooklikethis: entityManager.createNativeQuery(“SELECT*fromseat_type”).getResultList() Asyoucansee,itusesstandardSQLintheformofastring.Nowlet’slookatJPQL: entityManager.createQuery(“selectseatTypefromSeatType seatType”).getResultList(); It’seasytonoticeitssimilaritytoSQLbutabitdifferent.Ituses,forexample,classname insteadoftablename.However,again,it’saqueryinastring.Thelastexampleisthe CriteriaAPI: finalCriteriaQuery<SeatType>criteriaQuery= em.getCriteriaBuilder().createQuery(SeatType.class); criteriaQuery.select(criteriaQuery.from(SeatType.class)); em.createQuery(criteriaQuery).getResultList(); Atfirstglance,itlookslikethemostcomplicatedone,butithassomeadvantage,thatis,it doesnotuseanystrings(whichareusuallyerror-proneandhardtorefactor).BothJPQL andCriteriaAPIhavemanyimprovementsinthenewestJPAversion,concerningjoin operationsusingtheoncondition,databasefunctionssupport,andarithmeticsubqueries. Youmayaskyourself,“WhichoneshouldIuse?”It’sahardquestionbecauseallofthem havetheirprosandconssoitdependsonthespecificcase.Basically,Criteriaqueryand namedqueriesarenormallyasafebet.NativeSQLshouldhaveareallygoodjustification, asit’susuallynotportablebetweendifferentvendorsandcannotbevalidatedbyJPA beforetheexecution. Addingservicestoyourapplication Untilnow,wecodedalltheinformationthatwillbevisibletotheuserthroughthe applicationscreen.Whatisobviouslymissinghereisallthebusinesslogicthattranslates ultimatelyintoinsertingdataorupdatingtheexistingdata.Forthisreason,wewillnow addtwoclasses;first,undercom.packtpub.wflydevelopment.chapter5.control packageandsecondundercom.packtpub.wflydevelopment.chapter5.controller.The firstoneisTicketService,whichisastatelessEJBthatwillbeusedtoperformthecore businesslogicofthisapplication,andthesecondoneisourstatefulEJB’scounterpart, theBookerServiceclass.Let’sstartwiththestatelessEJB: @Stateless publicclassTicketService{ @Inject privateLoggerlog; @Inject privateEvent<SeatType>seatTypeEventSrc; @Inject privateEvent<Seat>seatEventSrc; @Inject privateSeatDaoseatDao; @Inject privateSeatTypeDaoseatTypeDao; publicvoidcreateSeatType(SeatTypeseatType)throwsException{ log.info(“Registering”+seatType.getDescription()); seatTypeDao.persist(seatType); seatTypeEventSrc.fire(seatType); } publicvoidcreateTheatre(List<SeatType>seatTypes){ for(SeatTypetype:seatTypes){ for(intii=0;ii<type.getQuantity();ii++){ finalSeatseat=newSeat(); seat.setBooked(false); seat.setSeatType(type); seatDao.persist(seat); } } } publicvoidbookSeat(longseatId){ finalSeatseat=seatDao.find(seatId); seat.setBooked(true); seatDao.persist(seat); seatEventSrc.fire(seat); } publicvoiddoCleanUp(){ seatDao.deleteAll(); seatTypeDao.deleteAll(); } } Tip WhyhasthiscomponentbeencodedasanEJBinsteadofaCDIBean? OneofthemainadvantagesofusingEJBsisthattheyareinherentlytransactional components.However,inJavaEE7,wecanuseCDIBeanswithanadditional @Transactionalannotation.Thechoicenowisuptothedeveloper,butEJBscanstill proveusefulinsomecases,evenforlocalcalls;forexample,wecaneasilydemarcate securityforthem(whichwewilldointhefuturechapters). Thisserviceismadeupoffourmethods.ThefirstisthecreateSeatTypemethod,which willbeusedinthefirstapplicationscreentoaddanewSeatTypeobjecttoourtheatre. Thenextmethod,createTheatre,willbeinvokedoncewearedonewithsettingupour theatre;sowecreatethelistofseatsthatwillbeavailableforbookinginthenextscreen. NextinthelististhebookSeatmethod,which,asyoumighthaveguessed,willbeusedto bookaseat.Finally,thedoCleanUpmethodisactuallyusedtoperformacleanupifyou wanttorestarttheapplication. ThelastpieceofourpuzzleistheBookerServiceclass,whichaddsatinysessionlayerto yourapplication: @Named @javax.faces.view.ViewScoped publicclassBookerServiceimplementsSerializable{ privatestaticfinallongserialVersionUID=-4121692677L; @Inject privateLoggerlogger; @Inject privateTicketServiceticketService; @Inject privateFacesContextfacesContext; privateintmoney; @PostConstruct publicvoidcreateCustomer(){ this.money=100; } publicvoidbookSeat(longseatId,intprice){ logger.info(“Bookingseat”+seatId); if(price>money){ finalFacesMessagem=new FacesMessage(FacesMessage.SEVERITY_ERROR,“NotenoughMoney!”, “Registrationsuccessful”); facesContext.addMessage(null,m); return; } ticketService.bookSeat(seatId); finalFacesMessagem=newFacesMessage(FacesMessage.SEVERITY_INFO, “Registered!”,“Registrationsuccessful”); facesContext.addMessage(null,m); logger.info(“Seatbooked.”); money=money-price; } publicintgetMoney(){ returnmoney; } } Theprecedingclassusestheviewscope,whichwealreadydescribedintheprevious chapters. Addingacontrollertodriveuserrequests Thelinkbetweenthepersistencelayerandtheuser’sviewfallsonthe TheatreSetupServicebean,whichwilldriverequeststotheactualservicesexposedby ourapplication.SincethisbeanwillbeboundtoRequestScopeandweneedtoexposeit toourviewsaswell(using@Named),wecanusetheconvenient@Modelannotationforit, whichisasumofthefollowingtwoattributes: @Model publicclassTheatreSetupService{ @Inject privateFacesContextfacesContext; @Inject privateTicketServiceticketService; @Inject privateList<SeatType>seatTypes; @Produces[1] @Named privateSeatTypenewSeatType; @PostConstruct publicvoidinitNewSeatType(){ newSeatType=newSeatType(); } publicStringcreateTheatre(){ ticketService.createTheatre(seatTypes); return“book”; } publicStringrestart(){ ticketService.doCleanUp(); return“/index”;[4] } publicvoidaddNewSeats()throwsException{ try{ ticketService.createSeatType(newSeatType); finalFacesMessagem=new FacesMessage(FacesMessage.SEVERITY_INFO,“Done!”,“SeatsAdded”); facesContext.addMessage(null,m); initNewSeatType(); }catch(Exceptione){ finalStringerrorMessage=getRootErrorMessage(e); FacesMessagem=newFacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage,“Errorwhilesavingdata”); facesContext.addMessage(null,m); } } privateStringgetRootErrorMessage(Exceptione){ //Defaulttogeneralerrormessagethatregistrationfailed. StringerrorMessage=“Registrationfailed.Seeserverlogformore information”; if(e==null){ //Thisshouldn’thappen,butreturnthedefaultmessages returnerrorMessage; } //Startwiththeexceptionandrecursetofindtherootcause Throwablet=e; while(t!=null){ //GetthemessagefromtheThrowableclassinstance errorMessage=t.getLocalizedMessage(); t=t.getCause(); } //Thisistherootcausemessage returnerrorMessage; } publicList<SeatPosition>getPositions(){ returnArrays.asList(SeatPosition.values()); } } TheTheatreSetupServiceclassisexpectedtocompletethefollowingtasks: 1. Atfirst,theTheatreSetupServiceclassproducesaSeatTypeobject[1]andexposes ittotheJSFViewlayerusingthe@Namedannotation. Tip ThistechniqueisagreatadditionprovidedbyCDIsinceitremovestheneedtocreate aboilerplateobject,SeatType,totransporttheinformationfromtheviewtothe services.TheSeatTypeobjectisproducedbythecontrollerandwillbepopulatedby theJSFviewandpersistedbytheTheatreSetupServiceclass. 2. Itthendrivesusernavigationbetweentheapplicationscreensbyreturningtothe homepage[4]. 3. WearedonewiththeJavaclasses.Youshouldnowchecktomakesurethatyour projectstructurematchesthefollowingscreenshot: CodingtheJSFview Nowthatourmiddletieriscompleted,wejustneedtoaddacoupleofJSFviewstoour applicationintheviewsfolderofourwebapp.Thefirstview,namedsetup.xhtml,will setupourtheatreandthesecondone,namedbook.xhtml,willbeusedtobooktickets, borrowingsomeofitscodefromtheearlierchapter. However,thistimewewouldliketomakeourapplicationalittlebitmoregraphically appealing.Tokeepitsimple,wewilluseBootstrap,averypopularfrontendframework thatwillnicelyintegratewithourJSFviews.ItheavilyreliesonJavaScriptandCSS,but wewillonlyneedtousebasicHTMLtogetitupandrunninginourapplication. Incorporatingastrictfrontendframeworktoourapplicationwillbeanopportunityto showhowtouseJavaEE7withthenewestwebtechnologies. YoucangetthelatestversionofBootstrapfromhttp://getbootstrap.com/andjustplaceall filesintheresourcesdirectory;however,wewon’tdoithere.WewillusetheWebJars, whicharesimplyJARsthatpackclient-sideweblibraries.Youcanfinddependenciesat http://www.webjars.org/,whichafteraddingtoyourpom.xmlfilewillworkjustlike manuallyaddingstaticfilestotheproject.However,thankstoWebJars,wegetMavento controlourversions,anddon’tneedtoworryaboutpollutingourcodebasewithexternal code. Now,weneedBootstrapandjQuery,sowewilladdthefollowingdependencies: <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>1.11.0</version> </dependency> Now,whenwehavetheBootstrap’slibrariesinplace,wehavetolinkthemtoourcode. WewilladdthemtoourWEB-INF/templates/default.xhtmlfilealongwithasimple navigationbar: <!DOCTYPEhtmlPUBLIC“-//W3C//DTDXHTML1.0Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”> <htmlxmlns=“http://www.w3.org/1999/xhtml” xmlns:h=“http://java.sun.com/jsf/html” xmlns:ui=“http://java.sun.com/jsf/facelets”> <h:head> <metahttp-equiv=“Content-Type”content=“text/html;charset=utf-8”/> <title>#{app.applicationName}</title> <metaname=“viewport”content=“width=device-width,initial-scale=1.0” /> <metaname=“description”content=””/> <metaname=“author”content=””/> <h:outputStylesheetname=”/webjars/bootstrap/3.2.0/css/bootstrap.css” /> <h:outputStylesheetname=”/webjars/bootstrap/3.2.0/css/bootstraptheme.css”/> <!—LeHTML5shim,forIE6-8supportofHTML5elements—> <!—[ifltIE9]> <scriptsrc=“http://html5shim.googlecode.com/svn/trunk/html5.js”> </script> <![endif]—> <style> body{ padding-top:60px; } </style> </h:head> <h:body> <divclass=“navbarnavbar-inversenavbar-fixed-top”role=“navigation”> <divclass=“container”> <divclass=“navbar-header”> <h:linkoutcome=”/index”class=“navbar-brand”value=“TicketAgency” /> </div> <divclass=“collapsenavbar-collapse”> <ulclass=“navnavbar-nav”> <liclass=”#{view.viewId==’/views/setup.xhtml’?‘active’:”}”> <h:linkoutcome=”/views/setup”value=“Theatresetup”/></li> <liclass=”#{view.viewId==’/views/book.xhtml’?‘active’:”}”> <h:linkoutcome=”/views/book”value=“Booktickets”/></li> </ul> </div> </div> </div> <divclass=“container”> <ui:insertname=“content”> [Templatecontentwillbeinsertedhere] </ui:insert> <hr/> <footer> <pclass=“text-muted”>©Company2014</p> </footer> </div> <h:outputScriptname=”/webjars/jquery/1.11.0/jquery.js”/> <h:outputScriptname=”/webjars/bootstrap/3.2.0/js/bootstrap.js”/> </h:body> </html> Next,wewillmovetothecontentinsetup.xhtml: <ui:compositionxmlns=“http://www.w3.org/1999/xhtml” xmlns:h=“http://xmlns.jcp.org/jsf/html” xmlns:f=“http://xmlns.jcp.org/jsf/core” xmlns:ui=“http://xmlns.jcp.org/jsf/facelets” template=”/WEB-INF/templates/default.xhtml” xmlns:p=“http://xmlns.jcp.org/jsf/passthrough”> <divclass=“jumbotron”> <h1>TheatreSetup</h1> <p>EntertheinformationaboutSeats</p> </div> <divclass=“row”> <divclass=“col-md-6”> <divclass=“panelpanel-default”> <divclass=“panel-heading”> <h3class=“panel-title”>Addseats</h3> </div> <divclass=“panel-body”> <h:formid=“reg”role=“form”> <divclass=“form-grouphas-feedback#{!desc.valid?‘has-error’: ”}”> <h:outputLabelfor=“desc”value=“Description” styleClass=“control-label”/> <h:inputTextid=“desc”value=”#{newSeatType.description}” p:placeholder=“Enteradescriptionhere”class=“form-control” binding=”#{desc}”/> <spanclass=”#{!desc.valid?‘glyphiconglyphicon-removeformcontrol-feedback’:”}”/> <h:messagefor=“desc”errorClass=“control-labelhas-error”/> </div> <divclass=“form-group#{!price.validand facesContext.validationFailed?‘has-error’:”}”> <h:outputLabelfor=“price”value=“Price:” styleClass=“control-label”/> <divclass=“input-grouphas-feedback”> <spanclass=“input-group-addon”>$</span> <h:inputTextid=“price”value=”#{newSeatType.price}” class=“form-control”p:placeholder=“Enteraprice” binding=”#{price}”/> <spanclass=”#{!price.valid?‘glyphiconglyphicon-remove input-group-feedbackinput-group-addon’:”}”/> </div> <h:messagefor=“price”errorClass=“control-labelhas-error”/> </div> <divclass=“form-grouphas-feedback#{!quantity.validand facesContext.validationFailed?‘has-error’:”}”> <h:outputLabelfor=“quantity”value=“NumberofSeats:” styleClass=“control-label”/> <h:inputTextid=“quantity”value=”#{newSeatType.quantity}” class=“form-control”p:placeholder=“Enterquantity” binding=”#{quantity}”/> <spanclass=”#{!quantity.valid?‘glyphiconglyphicon-remove form-control-feedback’:”}”/> <h:messagefor=“quantity”errorClass=“control-labelhas-error” /> </div> <divclass=“form-group”> <h:outputLabelfor=“position”value=“Position:” styleClass=“control-label”/> <h:selectOneMenuvalue=”#{newSeatType.position}”id=“position” class=“form-control”> <f:selectItemsvalue=”#{theatreSetupService.positions}” var=“pos”itemValue=”#{pos}”itemLabel=”#{pos.label}”/> </h:selectOneMenu> </div> <divclass=“form-group”> <h:commandButtonid=“Add”action=“#{theatreSetupService.addNewSeats}” value=“AddstyleClass=“btnbtn-primary”/> </div> <h:messagesstyleClass=“messages”style=“list-style:none; padding:0;margin:0;”errorClass=“alertalert-error”infoClass=“alert alert-success” warnClass=“alertalert-warning”globalOnly=“true”/> </h:form> </div> </div> </div> //somecode </div> </ui:define> </ui:composition> Asyoucansee,theprecedingviewcontainsaformtoenteranewseattypeinthetopmost section.ThehighlightedinputtextwillactuallypassdatatotheSeatTypeobject,which willbetransferredtotheTheatreSetupServiceCDIBeanandultimatelypersistedwhen theuserclicksontheAddbutton. Youmayalsonoticemanyclassattributesonthetags.TheseattributesrefertotheCSS classesdefinedbyBootstrap;weusethemtovisualizeourvalidation.Ifauserplaces someinvaliddatainaforminput,aproperCSSclassisassignedtoit(Bootstrap’shaserrormethodinourcase).Thisis,however,astrictlyfrontend-relatedaddition.TheJSF validationmessagewillbeshownwithorwithoutitthankstotheh:messagestagandthe BeanValidationconstraintsdefinedintheearlierpartofthischapter. AninterestingadditionisthefactthatweuseoneoftheJSF2.2features,whicheases integrationwithHTML5frontendframeworks,thepass-throughattributes.Byusingthe xmlns:p=http://xmlns.jcp.org/jsf/passthroughnamespaceinp:placeholder,we instructJSFtoignoreanunknownattributeandpassitstraighttotherenderer.Then, Bootstrap’sinternalmechanismscaninterprettheattribute,andprovideourinputcontrols withplaceholdertext,whichdisappearsafteracontrolgainsfocus. Thenextpartofthesetup.xhtmlfileisavailableinthefollowingcode: <divclass=“col-md-6”> <divclass=“panelpanel-default”> <divclass=“panel-heading”> <h2class=“panel-title”>SeatsList</h2> </div> <divclass=“panel-body”> <h:formid=“reg2”> <h:commandButtonid=“Finish” action=”#{theatreSetupService.createTheatre}” value=“Finalizethetheatresetup” styleClass=“btnbtn-defaultbtn-block”/> </h:form> </div> <h:panelGrouprendered=”#{emptyseatTypes}”> <em>NoSeatsAdded.</em> </h:panelGroup> <h:dataTablevar=“seatType”value=”#{seatTypes}” rendered=”#{notemptyseatTypes}” styleClass=“tabletable-hovertable-striped“> <h:column> <f:facetname=“header”>Id</f:facet> #{seatType.id} </h:column> <h:column> <f:facetname=“header”>Name</f:facet> #{seatType.description} </h:column> <h:column> <f:facetname=“header”>Position</f:facet> #{seatType.position.label} </h:column> <h:column> <f:facetname=“header”>Price</f:facet> $#{seatType.price} </h:column> <h:column> <f:facetname=“header”>Quantity</f:facet> #{seatType.quantity} </h:column> </h:dataTable> </div> </div> </div> </ui:define> Eachtimeyouaddanewblockofseatstoyourtheatre,thedataTablemethodcontained inthelowerpartofthescreenwillbeupdated.Whenyouaredonewithyoursetup,click ontheFinishbutton,whichwillrecallthefinishmethodoftheTheatreSetupService CDIBean,creatingthelistofseats. Thisactionwillalsoredirectyoutothenextview,namedbook.xhtml,whichisusedto bookseats: <ui:definename=“content”> <divclass=“page-header”> <h2>TicketBookerMachine</h2> </div> <h3>Money:$#{bookerService.money}</h3> <h:formid=“reg”> <h:messagesstyleClass=“messages” style=“list-style:none;padding:0;margin:0;” errorClass=“alertalert-error”infoClass=“alertalert-success” warnClass=“alertalert-warning”globalOnly=“true”/> <h:commandButtonid=“restart”action=”# {theatreSetupService.restart}” value=“RestartApplication”class=“btnbtn-default”/> <h:dataTablevar=“seat”value=”#{seats}” rendered=”#{notemptyseats}” styleClass=“tabletable-hovertable-striped“> <h:column> <f:facetname=“header”>Id</f:facet> #{seat.id} </h:column> <h:column> <f:facetname=“header”>Description</f:facet> #{seat.seatType.description} </h:column> <h:column> <f:facetname=“header”>Price</f:facet> #{seat.seatType.price}$ </h:column> <h:column> <f:facetname=“header”>Position</f:facet> #{seat.seatType.position.label} </h:column> <h:column> <f:facetname=“header”>Booked</f:facet> <spanclass=“glyphiconglyphicon-#{seat.booked?‘ok’ :‘remove’}”></span> </h:column> <h:column> <f:facetname=“header”>Action</f:facet> <h:commandButtonid=“book” action=”#{bookerService.bookSeat(seat.id, seat.seatType.price)}” disabled=”#{seat.booked}”class=“btnbtn-primary” value=”#{seat.booked?‘Reserved’:‘Book’}”/> </h:column> </h:dataTable> </h:form> </ui:define> Here’sasnapshotoftheproject,expandedatthewebapplevel(asyoucansee,wehave alsoincludedabasicindex.htmlscreenandanindex.xhtmlscreentoredirecttheuserto theinitialscreen,setup.xhtml): Runningtheexample Deployingtheapplicationrequires,asusual,packagingitusingthefollowingMavengoal: mvnpackage [INFO]Scanningforprojects… [INFO] [INFO]––––––––––––––––––––– [INFO]Buildingticket-agency-jpa1.0 [INFO]––––––––––––––––––––– [INFO]Buildingwar:C:\chapter5\ticket-agency-jpa\target\ticket-agencyjpa.war …. [INFO]––––––––––––––––––––– [INFO]BUILDSUCCESS [INFO]––––––––––––––––––––– [INFO]Totaltime:1.799s Finally,providedthatyouhaveinstalledtheWildFlyMavenplugin,youcandeployyour applicationusingthefollowingcommand: mvnwildfly:deploy Oncethedeploymenthassuccessfullycompleted,visithttp://localhost:8080/ticketagency-jpa/toviewtheapplication’swelcomepage,asshowninthefollowing screenshot: Congratulations!You’redone.ByclickingontheSetupTheatrelink,youcanstart creatingplacesinthesetup.xhtmlpage.Feelfreetoexperimentwiththeinputs,andtry tofillsomelettersinthepriceboxornumbersinthedescription,asshowninthe followingscreenshot: OnceyouclickontheFinalizethetheatresetupbutton,youwillberedirectedtothelast screen,whichperformsseatbookinginbook.xhtml: Summary TheaimofthenewJavaPersistenceAPIistosimplifythedevelopmentofpersistent entities.ItmeetsthisobjectivethroughasimplePOJO-basedpersistencemodel,which reducesthenumberofrequiredclassesandinterfaces. Inthischapter,wecoveredalotofground,startingwiththedatabaseschemathatwe reverseengineeredusingtheJBosstoolspluginsforEclipse.Next,wecodedthesetof layers(producers,services,andcontrollers)thatarepartoftheapplication,alongwiththe JSFFacelets. Inthenextchapter,wewilldiscussdevelopingapplicationsusingJBossMessaging Provider(HornetQ)byintroducingexampleswithmessage-drivenbeansusingthenew simplifiedJavaEE7API. Chapter6.DevelopingApplicationswith JBossJMSProvider Messagingisamethodofcommunicationbetweensoftwarecomponentsandapplications. JavaMessageService(JMS)isaJavaAPI—designedoriginallybySun—thatallows applicationstocreate,send,receive,andreadmessages.Thenew2.0versionoftheAPI hasbeenintroducedwithJSR343(https://jcp.org/en/jsr/detail?id=343). Messagingdiffersfromotherstandardprotocols,suchasRemoteMethodInvocation (RMI)orHypertextTransferProtocol(HTTP),intwoways.First,theconversationis mediatedbyamessagingserversoit’snotatwo-wayconversationbetweenpeers.Second, thesenderandthereceiverneedtoknowwhatmessageformatandwhatdestinationto use.Thisisincontrasttotightlycoupledtechnologies,suchasRemoteMethodInvocation (RMI),thatrequireanapplicationtoknowaboutaremoteapplication’smethods. Inthischapter,wewillcoverthefollowing: Abriefintroductiontomessage-orientedsystems ThebuildingblocksoftheJBossmessagingsubsystem Settingupproofofconceptprogrammingexamples HowtouseJMSandresourceadapterstointegratewithexternalsystems AshortintroductiontoJMS JMSdefinesavendor-neutral(butJava-specific)setofprogramminginterfacestointeract withasynchronousmessagingsystems.Messagingenablesdistributedcommunicationthat islooselycoupled.Thewholemessaginginterchangeisatwo-stepprocesswherea componentsendsamessagetoadestinationthatisinturnretrievedbytherecipientwith themediationoftheJMSserver.InJMS,therearetwotypesofdestinations:topicsand queues.Thesehavedifferentsemantics,whichareexplainednext. Inapoint-to-pointmodel,messagesaresentfromproducerstoconsumersviaqueues.A givenqueuemighthavemultiplereceivers,butonlyonereceiverwouldbeableto consumeeachofthemessages.Onlythefirstreceiverwhorequeststhemessagewillget it,whiletheotherswillnot,asshowninthefollowingimage: Amessagesenttoatopic,ontheotherhand,mightbereceivedbymultipleparties. Messagespublishedonaspecifictopicaresenttoallthemessageconsumerswhohave registered(subscribed)themselvestoreceivemessagesonthattopic.Asubscriptioncan bedurableornondurable.Anondurablesubscribercanonlyreceivemessagesthatare publishedwhileitisactive.Anondurablesubscriptiondoesnotguaranteethedeliveryof amessage;itmightdeliverthesamemessagemorethanonce.Adurablesubscription,on theotherhand,guaranteesthattheconsumerreceivesthemessageexactlyonce,as depictedinthefollowingimage: Asfarasmessageconsumptionisconcerned,eventhoughJMSisinherently asynchronous,theJMSspecificationallowsmessagestobeconsumedineitherofthe followingtwoways: Synchronously:Asubscriberorareceiverexplicitlyfetchesthemessagefromthe destinationbycallingthereceive()methodofanyMessageConsumerinstance.The receive()methodcanblockuntilamessagearrivesorcantakeatimeoutifa messagedoesnotarrivewithinaspecifiedtimelimit. Asynchronously:Withtheasynchronousmode,theclientmustimplementthe javax.jms.MessageListenerinterfaceandoverwritetheonMessage()method. Wheneveramessagearrivesatthedestination,theJMSproviderdeliversthe messagebycallingthelistener’sonMessagemethod,whichactsonthecontentsof themessage. AJMSmessageconsistsofaheader,properties,andabody.Themessageheadersprovide afixedsetofmetadatafieldsthatdescribethemessagewithinformationsuchaswherethe messageisgoingandwhenitisreceived.Thepropertiesareasetofkey-valuepairsused forapplication-specificpurposes,usuallytohelpfiltermessagesquicklywhentheyare received.Finally,thebodycontainswhateverdataisbeingsenttothemessage. TheJMSAPIsupportstwodeliverymodesformessagestospecifywhetherornotthe messagesarelostiftheJMSproviderfails,indicatedbythefollowingconstants: Thepersistentdeliverymode,whichisthedefault,instructstheJMSprovidertotake extracaretoensurethatamessageisnotlostintransitinthecaseofaJMSprovider failure.Amessagesentwiththisdeliverymodeisloggedtostablestoragewhenitis sent. ThenonpersistentdeliverymodedoesnotrequiretheJMSprovidertostorethe messageorotherwiseguaranteethatitisnotlostiftheproviderfails. ThebuildingblocksofJMS ThebasicbuildingblocksofanyJMSapplicationconsistofthefollowing: Administeredobjects—connectionfactoriesanddestinations Connections Sessions Messageproducers Messageconsumers Messages Let’stakeacloserlookatthem: Connectionfactory:Thisobjectencapsulatesasetofconnectionconfiguration parametersthathavebeendefinedbyanadministrator.Aclientusesittocreatea connectionwithaJMSprovider.Aconnectionfactoryhidesprovider-specificdetails fromJMSclientsandabstractsadministrativeinformationintoobjectsintheJava programminglanguage. Destination:Thisisthecomponentaclientusestospecifythetargetofmessagesit producesandthesourceofmessagesitconsumes.Inthepoint-to-point(PTP) messagingdomain,destinationsarecalledqueues;inthepublish/subscribe (pub/sub)messagingdomain,destinationsarecalledtopics. Connection:ThisencapsulatesavirtualconnectionwithaJMSprovider.A connectioncouldrepresentanopenTCP/IPsocketbetweenaclientandaprovider service.Youuseaconnectiontocreateoneormoresessions. Session:Thisisasingle-threadedcontextforproducingandconsumingmessages. Youusesessionstocreatemessageproducers,messageconsumers,andmessages. Sessionsserializetheexecutionofmessagelistenersandprovideatransactional contextwithwhichtogroupasetofsendsandreceivesintoanatomicunitofwork. Messageproducer:Thisisanobjectcreatedbyasessionandisusedtosend messagestoadestination.ThePTPformofamessageproducerimplementsthe QueueSenderinterface.Thepub/subformimplementstheTopicPublisherinterface. FromJMS2.0,itispossibletorelyonlyontheJMSProducerinterface. Messageconsumer:Thisisanobjectcreatedbyasessionandisusedtoreceive messagessenttoadestination.AmessageconsumerallowsaJMSclienttoregister interestinadestinationwithaJMSprovider.TheJMSprovidermanagesthedelivery ofmessagesfromadestinationtotheregisteredconsumersofthedestination.The PTPformofmessageconsumerimplementstheQueueReceiverinterface.The pub/subformimplementstheTopicSubscriberinterface.ThelatestJMSversion supportsanewJMSConsumerAPI. TheJBossmessagingsubsystem JBossAShasuseddifferentJMSimplementationsacrossitsreleases,suchasJBossMQ andJBossMessaging.SinceJBossAS6.0,thedefaultJMSproviderisHornetQ (http://www.jboss.org/hornetq),whichprovidesamultiprotocol,embeddable,highperformant,andclusterablemessagingsystem. Atitscore,HornetQisdesignedsimplyasasetofPlainOldJavaObjects(POJOs)with fewdependenciesonexternalJARfiles.Infact,theonlyoneJARdependencyistheNetty library,whichleveragestheJavaNewInput-Output(NIO)APItobuildhighperformancenetworkapplications. Becauseofitseasilyadaptablearchitecture,HornetQcanbeembeddedinyourown projectorinstantiatedinanydependencyinjectionframeworksuchas JBossMicrocontainer,Spring,orGoogleGuice. Inthisbook,wewillcoverascenariowhereHornetQisintegratedintotheWildFly subsystemasamodule,asshowninthefollowingdiagram.Thisdiagramdepictshowthe JCAAdapterandtheHornetQserverfitintheoverallpicture: Creatingandusingconnectionfactories Itisthejoboftheconnectionfactorythatencapsulatestheconnection’sparametersto createnewJMSconnections.AconnectionfactoryisboundtotheJavaNaming DirectoryIndex(JNDI)andcanbelookedupbybothlocalandremoteclients,provided theysupplythecorrectenvironmentparameters.Sinceaconnectionfactorycanbereused multipletimesinyourcode,it’sthekindofobjectthatcanbeconvenientlycachedbya remoteclientoramessage-drivenbean. Thedefinitionofconnection-factoryinstancesisincludedinthefullandfull-haserver configurations.Youcanchooseeitheroftheserverconfigurationsusingthe–ccommand argument,forinstance,standalone.bat–cstandalone-full.xml.Wewillcoverthe configurationprofilesindepthinChapter9,ManagingtheApplicationServer.Fornow, justremembertostartyourserverwiththefullconfigurationprofilewheneveryouneed JMS. YoucaninspecttheconnectionfactoriesintheoverallJMSconfiguration,whichis availablebysurfingtheadminconsoleandnavigatingtoConfiguration|Messaging Destinations|ConnectionFactories,asshowninthefollowingscreenshot: Asyoucanseeinthepreviousscreenshot,therearethefollowingtwoout-of-the-box connection-factorydefinitions: InVmConnectionFactory:Thisconnectionfactoryisboundunderthe java:/ConnectionFactoryentryandisusedwhentheserverandclientarepartof thesameprocess(thatis,theyarerunningonthesameJVM). RemoteConnectionFactory:Thisconnectionfactoryisboundedunderthe java:jboss/exported/jms/RemoteConnectionFactoryentry,andasthename implies,itcanbeusedusingNettyastheconnectorwhenJMSconnectionsare providedbyaremoteserver. Ifyouwanttochangetheconnectionfactory’sJNDIbinding,thesimplestchoiceistogo throughtheserverconfigurationfile(forexample,standalone-full.xml,fora standalonemode): <connection-factoryname=“InVmConnectionFactory”> <connectors> <connector-refconnector-name=“in-vm”/> </connectors> <entries> <entryname=“java:/ConnectionFactory”/> </entries> </connection-factory> <connection-factoryname=“RemoteConnectionFactory”> <connectors> <connector-refconnector-name=“http-connector”/> </connectors> <entries> <entryname=“java:jboss/exported/jms/RemoteConnectionFactory”/> </entries> </connection-factory> <pooled-connection-factoryname=“hornetq-ra”> <transactionmode=“xa”/> <connectors> <connector-refconnector-name=“in-vm”/> </connectors> <entries> <entryname=“java:/JmsXA”/> <entryname=“java:jboss/DefaultJMSConnectionFactory”/> </entries> </pooled-connection-factory> TheconnectionfactorycanbeinjectedjustlikeanyotherJavaEEresource;thefollowing codefragmentshowshowastatelessEJBgetsthedefaultconnectionfactoryinjected: @Stateless publicclassSampleEJB{ @Resource(mappedName=“java:/ConnectionFactory”) privateConnectionFactorycf; } Note Inordertousethemessagingsubsystem,youhavetostartWildFlyusingaJavaEEfull profile,whichincludesthemessagingsubsystem.So,forexample,ifyouwanttostarta standaloneserverinstancethatisJMS-aware,youcansimplyusethefollowingcode: standalone.sh–cstandalone-full.xml UsingJMSdestinations Alongwiththedefinitionofconnectionfactories,youwillneedtolearnhowtoconfigure JMSdestinations(queuesandtopics). Thiscanbeachievedwithavarietyofinstruments.Sincewehavestarteddealingwiththe webconsole,justnavigatetotheConfigurationtabandpicktheMessagingsubsystem fromtheleftpanel.SelectDestinationsandclickontheViewcentrallink. Fromthere,youcanusetheuppermenutabthatcontainsasetofoptions,thefirstoneof which—namedQueues/Topics—canbeusedtoconfigureyourJMSdestinations,as showninthefollowingscreenshot: NowclickontheAddbutton.Youshouldseethefollowingdialog: EnterthemandatorynameforyourdestinationanditsJNDI.Youcanoptionallychooseto defineyourJMSdestinationaseitherofthefollowingoptions: Durable:ThisoptionallowstheJMSservertoholdontoamessageincasethe subscriberistemporarilyunavailable. Selector:ThisoptionallowsafiltertotheJMSdestination(wewillcoverthisin greaterdetaillaterinthischapter). ClickontheSavebuttonandverifythatthequeuehasbeenenlistedamongtheJMS destinations. Theprecedingchangewillreflectintheserverconfigurationfileasfollows: <jms-destinations> <jms-queuename=“TicketQueue”> <entryname=“java:jboss/jms/queue/ticketQueue”/> <durable>false</durable> </jms-queue> </jms-destinations> It’sworthnotingthattheJMSconfigurationusuallydiffersoneveryapplicationserver.In thischapter,wewillcoveronlytheapproachusedinWildFly,butthekeyconcepts betweendifferentprovidersstaythesame. Addingmessage-drivenbeanstoyourapplication Oncewedotheconfiguration,wecanstartcodingaJMSmessageconsumer,suchasa message-drivenbean. Message-drivenbeans(MDBs)arestateless,server-side,andtransaction-aware componentsthatprocessasynchronousJMSmessages. Oneofthemostimportantaspectsofmessage-drivenbeansisthattheycanconsumeand processmessagesconcurrently.Thiscapabilityprovidesasignificantadvantageover traditionalJMSclients,whichmustbecustombuilttomanageresources,transactions,and securityinamultithreadedenvironment.MDBcontainersmanageconcurrency automaticallysothebeandevelopercanfocusonthebusinesslogicofprocessingthe messages.AnMDBcanreceivehundredsofJMSmessagesfromvariousapplicationsand processthemallatthesametimebecausenumerousinstancesofitcanbeexecuted concurrentlyinthecontainer. Fromthesemanticpointofview,anMDBisclassifiedasanenterprisebean,justlikea sessionorentitybean,buttherearesomeimportantdifferences.Atfirst,themessagedrivenbeandoesnothavecomponentinterfaces.TheseareabsentbecausethemessagedrivenbeanisnotaccessibleviatheJavaRMIAPI;itrespondsonlytoasynchronous messages. Justastheentityandsessionbeanshavewell-definedlifecycles,sodoestheMDBbean. TheMDBinstance’slifecyclehastwostates,DoesnotExistandMethodreadyPool,as showninthefollowingimage: Whenamessageisreceived,theEJBcontainercheckstoseewhetheranyMDBinstance isavailableinthepool.Ifabeanisavailableinthefreepool,JBossusesthatinstance. OnceanMDBinstance’sonMessage()methodisreturned,therequestiscompleteandthe instanceisplacedbackinthefreepool.Thisresultsinthebestresponsetime,asthe requestisservedwithoutwaitingforanewinstancetobecreated. Note Ontheotherhand,ifalltheinstancesinthepoolarebusy,thenewrequestwillbe serializedsinceit’sguaranteedthatthesameinstancewillnotbeallowedtoservemultiple clientsatthesametime.Also,ifaclientsendsoutmultiplemessagestotheserver containinganMDB,thereisnoguaranteethatthesameMDBinstancewillbeusedfor eachmessageorthatthemessageswillbeprocessedintheorderinwhichtheclientsent them.Thismeansthattheapplicationshouldbedesignedtohandlemessagesthatarrive outoforder. ThenumberofMDBsinthepoolisconfiguredintheEJBpool,whichcanbereached fromtheconsolebynavigatingtoConfiguration|Container|EJB3|BeanPoolsas depictedinthefollowingscreenshot: Thebeanpool’sconfigurationiscontainedinthebeanpoolcentraltab,whichholdsboth thestatelessandMDBpoolconfigurations.ThedefaultvaluefortheMDB’smaxpool sizeis20units. Itisalsopossibletooverridepoolsforspecificbeans.YoucanuseeithertheJBossspecificorg.jboss.ejb3.annotation.Poolannotationorthejboss-ejb3.xml deploymentdescriptor.Formoreinformationonoverridingpoolsforthechosenbeans, visithttps://docs.jboss.org/author/display/WFLY8/EJB3+subsystem+configuration+guide. Ifnobeaninstancesareavailable,therequestwillbeblockeduntilanactiveMDB completesamethodcallorthetransactiontimesout. Cookingmessage-drivenbeans Wewillnowaddamessage-drivenbeantoourapplicationfromthepreviouschapter, whichwillbeusedtointerceptmessageswhenanewticketisbooked.Forthepurposeof ourexample,wewilljusttracewhethertheJMSmessagehasbeenreceived;however,you canalsouseitformorecomplexpurposessuchasnotifyingexternalsystems. CreateanewJavaclass,sayBookingQueueReceiver,andenterthepackagenameas com.packtpub.wflydevelopment.chapter6.jms. Oncedone,let’saddtheMDBconfigurationviaanannotation,asshownhere: packagecom.packtpub.wflydevelopment.chapter6.jms; importjavax.ejb.ActivationConfigProperty; importjavax.ejb.MessageDriven; importjavax.inject.Inject; importjavax.jms.JMSException; importjavax.jms.Message; importjavax.jms.MessageListener; importjava.util.logging.Logger; @MessageDriven(name=“BookingQueueReceiver”,activationConfig={ @ActivationConfigProperty(propertyName=“destinationLookup”, propertyValue=“java:jboss/jms/queue/ticketQueue”),[1] @ActivationConfigProperty(propertyName=“destinationType”, propertyValue=“javax.jms.Queue”),} ) publicclassBookingQueueReceiverimplementsMessageListener{ @Inject privateLoggerlogger; @Override publicvoidonMessage(Messagemessage){ try{ finalStringtext=message.getBody(String.class); logger.info(“Receivedmessage”+text); }catch(JMSExceptionex){ logger.severe(ex.toString()); } } } HerewehaveconnectedtheMDBtoourticketQueuedestination[1]boundat java:jboss/jms/queue/ticketQueue.Thepurposeofthiscomponentwillbetotracethe messagereceiptviajava.util.Logger. JavaEE7introducesanadditionalwayofthequeuedefinition.Now,youdon’thaveto addaqueuefromtheapplicationservermanagementtool.Itispossibletodefinequeues andtheirpropertiesinthecodeusingsomebasicannotations: packagecom.packtpub.wflydevelopment.chapter6.jms; importjavax.jms.JMSDestinationDefinition; @JMSDestinationDefinition( name=BookingQueueDefinition.BOOKING_QUEUE, interfaceName=“javax.jms.Queue” ) publicclassBookingQueueDefinition{ publicstaticfinalStringBOOKING_QUEUE= “java:global/jms/bookingQueue“; } Then,inBookingQueueReceiver,youcanjustchangepropertyValue= “java:jboss/jms/queue/ticketQueue”topropertyValue= BookingQueueDefinition.BOOKING_QUEUE. AddingtheJMSproducer Oncewe’redonewiththeJMSconsumer,weneedacomponentthatwilltakecareof sendingJMSmessages.Forthispurpose,wewilladdanApplicationScopedCDIBean, sayBookingQueueProducer,whichgetsinjectedintheJMSresources: packagecom.packtpub.wflydevelopment.chapter6.jms; importjavax.annotation.Resource; importjavax.enterprise.context.RequestScoped; importjavax.inject.Inject; importjavax.jms.JMSContext; importjavax.jms.Queue; @ApplicationScoped publicclassBookingQueueProducer{ @Inject privateJMSContextcontext; @Resource(mappedName=BookingQueueDefinition.BOOKING_QUEUE) privateQueuesyncQueue; publicvoidsendMessage(Stringtxt){ context.createProducer().send(syncQueue,txt); } } ThismightbeabitshockingforthosewhohaveusedthepreviousversionsoftheJMS. Forthosewhohaven’t,inthefollowingcodewepresentthiscode’sequivalentinJMS1.1: packagecom.packtpub.wflydevelopment.chapter6.jms; Importjavax.annotation.Resource; Importjavax.enterprise.context.ApplicationScoped; Importjavax.jms.*; Importjava.util.logging.Logger; @ApplicationScoped publicclassBookingQueueProducer{ @Inject privateLoggerlogger; @Resource(mappedName=“java:/ConnectionFactory”) privateConnectionFactorycf; @Resource(mappedName=BookingQueueDefinition.BOOKING_QUEUE) privateQueuequeueExample; publicvoidsendMessage(Stringtxt){ try{ finalConnectionconnection=cf.createConnection(); Sessionsession=connection .createSession(false,Session.AUTO_ACKNOWLEDGE); finalMessageProducerpublisher= session.createProducer(queueExample); connection.start(); finalTextMessagemessage= session.createTextMessage(txt); publisher.send(message); } catch(Exceptionexc){ logger.error(“Error!“+exc); } finally{ if(connection!=null){ try{ connection.close(); }catch(JMSExceptione){ logger.error(e); } } } } } Codeamountchangeisimpressive.APIsimplificationwasoneofthemajorfeaturesof thenewJMSversion,andthespecificationauthorsdidgreatworkonit. Now,youcanuseyourservicetonotifysomeapplication-specificactions.Forexample, wewillinjectBookingQueueProducerintotheBookerServicebeanandsendamessage wheneverauserisregistered: publicclassBookerServiceimplementsSerializable{ @Inject privateBookingQueueProducerbookingQueueProducer; //Somecode publicvoidbookSeat(longseatId,intprice){ logger.info(“Bookingseat”+seatId); if(price>money){ finalFacesMessagem= newFacesMessage(FacesMessage.SEVERITY_ERROR, “NotenoughMoney!”, “Registrationsuccessful”); facesContext.addMessage(null,m); return; } ticketService.bookSeat(seatId); finalFacesMessagem= newFacesMessage(FacesMessage.SEVERITY_INFO, “Registered!”, “Registrationsuccessful”); facesContext.addMessage(null,m); logger.info(“Seatbooked.”); money=money-price; bookingQueueProducer.sendMessage(“[JMSMessage]Userregistered seat”+seatId); } //Somecode } FromJMS2.0,messagescanbesentasynchronously,butthenitisimportanttocontrol whethertheoperationsaresuccessfulornot.Todothis,wehavetocreateanobjectthat implementstheCompletionListenerinterface,asfollows: @ApplicationScoped publicclassBookingCompletionListenerimplementsCompletionListener{ @Inject privateLoggerlogger; @Override publicvoidonCompletion(Messagemessage){ try{ finalStringtext=message.getBody(String.class); logger.info(“Sendwassuccessful:”+text)); }catch(Throwablee){ logger.severe(“Problemwithmessageformat”); } } @Override publicvoidonException(Messagemessage,Exceptionexception){ try{ finalStringtext=message.getBody(String.class); logger.info(“Sendfailed…”+text); }catch(Throwablee){ logger.severe(“Problemwithmessageformat”); } } } Duringthesendoperation,wehavetospecifytheasynchronousandusethislistener object.Todothis,injectBookingCompletionListenertoBookingQueueProducerand sendmessageswithanupdatedcall: publicvoidsendMessage(Stringtxt){ context.createProducer() .setAsync(bookingCompletionListener).send(syncQueue,txt); } Now,appropriatelistenermethodswillbeexecutedwhenthemessagesendiscompleted orfailed: [com.packtpub.wflydevelopment.chapter6.jms.BookingCompletionListener] (Thread-3(HornetQ-client-global-threads-269763340))Sendwassuccessful: [JMSMessage]Userregisteredseat2 Compilinganddeployingtheapplication WehavebasedourcodeontheJPAapplicationfromthepreviouschapter.Thanksto javaee-api,youdon’thavetoaddanynewprojectdependenciesinordertouseJMS! TheonlythingyouhavetodoistostartWildFlyinfullprofileusing,forexample, standalone-full.xmlstandalone-full.xml—thestandardfullprofileconfiguration: standalone.sh–cstandalone-full.xml Note Remember,whenswitchingtoanotherserverconfiguration,youwillneedtorecreateall theexampleresources,suchasdatasources,thatweresetupinitiallyforyourstandalone configuration. NowdeployyourapplicationusingeitherEclipse’sServervieworMavenandaccessthe applicationathttp://localhost:8080/ticket-agency-jms/. EverythingshouldworkjustliketheearlierJPAproject;however,inyourapplication serverconsole,youshouldnoticethemessagesthatconfirmaseathasbeenbooked. Specifyingwhichmessagetoreceiveusingselectors MessageselectorsallowanMDBtobemoreselectiveaboutthemessagesitreceivesfrom aparticulartopicorqueue.Messageselectorsusemessagepropertiesascriteriain conditionalexpressions.Messageproperties,uponwhichmessageselectorsarebased,are additionalheadersthatcanbeassignedtoamessage.Theygivetheapplicationdeveloper theabilitytoattachmoreinformationtoamessage.Thisinformationcanbestoredusing severalprimitivevalues(boolean,byte,short,int,long,float,anddouble)oras String. Forexample,let’ssupposethatwewanttoprocesstwokindsofmessageswiththesame queue: Atracemessageindicatingthatauserhasbookedaseat Awarningmessageindicatingthatanerrorhasoccurred Hence,oursendMessagemethodcanbechangedslightlytoincludeaStringpropertythat canbeattachedtothemessage: @ApplicationScoped publicclassBookingQueueProducer{ @Inject privateJMSContextcontext; @Inject privateBookingCompletionListenerbookingCompletionListener; @Resource(mappedName=BookingQueueDefinition.BOOKING_QUEUE) privateQueuesyncQueue; publicvoidsendMessage(Stringtxt,Prioritypriority){ context.createProducer() .setAsync(bookingCompletionListener) .setProperty(“priority”,priority.toString()) .send(syncQueue,txt); } } publicenumPriority{ LOW,HIGH } Now,inourapplicationcontext,wemightusethesendMessagemethod,attachingaLOW valueforprioritywhentheuserisregistered: bookingQueueProducer.sendMessage(“[JMSMessage]Userregisteredseat”+ seatId,Priority.LOW); Ontheotherhand,wecouldattachaHIGHprioritywhenanerroroccurs: bookingQueueProducer.sendMessage(“ErrorduringTransaction”,Priority. HIGH); FromtheMDBperspective,allyouneedtodoinordertofilterthroughmessagesis includethemessageselectoraspartofyourActivationConfigPropertyclassasfollows: @MessageDriven(name=“BookingQueueReceiver”,activationConfig={ @ActivationConfigProperty(propertyName=“destinationLookup”, propertyValue=BookingQueueDefinition.BOOKING_QUEUE), @ActivationConfigProperty(propertyName=“destinationType”, propertyValue=“javax.jms.Queue”), @ActivationConfigProperty(propertyName=“messageSelector”, propertyValue=“priority=‘HIGH’”),} ) publicclassBookingQueueReceiverimplementsMessageListener{ //Somecode } Atthesametime,youcandeployanotherMDBthatisinchargeofconsumingmessages thataresentwithaLOWpriority: @MessageDriven(name=”LowPriorityBookingQueueReceiver”,activationConfig ={ @ActivationConfigProperty(propertyName=“destinationLookup”, propertyValue=BookingQueueDefinition.BOOKING_QUEUE), @ActivationConfigProperty(propertyName=“destinationType”, propertyValue=“javax.jms.Queue”), @ActivationConfigProperty(propertyName=“messageSelector”, propertyValue=“priority=‘LOW’”),} ) publicclassLowPriorityBookingQueueReceiverimplementsMessageListener{ //Somecode } Whentalkingaboutfiltering,wehavetosayafewwordsconcerningperformance.In HornetQqueuesandtopics,therearefilteringmessagesonadifferentstage.Inthecaseof queues,propertiesarefilteredwhentheyhavealreadybeenreceivedbythelistener,while intopics,theyarefilteredbeforebeingadded.KeepinmindthisisnotguaranteedbyJMS specification(sinceaspecificationdescribestheAPI)andmightactdifferentlyinother implementations.TherearealotofperformanceoptionsthatcanbetunedinJMS providers;however,mostoftheconfigurationsmustbespecificallychosenforevery project.BesuretocheckadditionaltuningtipsinHornetQ’sdocumentationat http://docs.jboss.org/hornetq/2.4.0.Final/docs/user-manual/html_single/#perf-tuning. Transactionandacknowledgmentmodes Inordertocontroltheoverallperformanceandreliabilityofanasynchronousmessaging system,weneedtotaketwofactorsintoaccount:persistingofmessagesand acknowledgment.Let’stakealookatthosecharacteristics. Reliabilityofthesystemisfocusedontheabilitytodelivermessagesexactlyonce.This meansthatnomessageislost,andtherearenoduplicates.Formostsystems,itisastrong requirementthatyoudon’tmissorduplicateanyorders(likeinane-commercesite). However,usuallyitisnotaproblemtomissanupdatefromthestockmarketbecausea neweronewouldoverwriteitinamoment.Ofcourse,additionalfeaturessuchas reliabilitycomeataprice,andinthecaseofJMS,thepriceispaidinperformance.The morereliablethesystem,theloweritsmessagethroughputis. Whenamessageisprocessed,itcanbeheldonlyinthememoryorpersistedsomewhere onthedisk.Messagesstoredinthememoryarelostinthecaseofafailureorwhenthe messagingserviceisstopped.Persistedmessagescanberetrievedfromthediskafterthe serviceisrestartedandthereforedeliveredtotheconsumersatleastonce(butstillwithout anyguaranteesabouttheacknowledgment).Withoutthismechanism,messagescan potentiallybelostinthesystembecauseafailuremightoccurbeforetheyaredelivered. However,theoverheadofstoringthemcanhaveaseriousimpactonthesystem’s performancecharacteristics. AcknowledgmentisimportanttoinformtheJMSservicethatthemessagewasreally receivedandprocessedbytheconsumer.Differentlevelsofacknowledgmentscanbeused toavoidduplicatesortotriggerJMStosendthemessageoncemore,possiblytoanother consumer.AJMSproviderwillensurethatanacknowledgedmessageisdeliveredonly once.Theapplicationisresponsibleforproperlyhandlingrolledbackmessagesthatwere redelivered(suchmessagesaremarkedwiththeJMSRedeliveredheader). Iftheconsumersessionishandledinatransaction,thenthemessagesareacknowledged onlywhenthetransactioniscommitted.However,thereisanoptiontodisable transactionalmessage-drivenbeansandmanuallyhandletheacknowledgment.Inthis case,therearethefollowingthreetypesofacknowledgementoptions: AUTO_ACKNOWLEDGE:Withthis,theconsumedmessagesarebeing acknowledgedautomatically DUPS_OK_ACKNOWLEDGE:Withthis,thedeliveredmessagesarebeinglazily acknowledged;thismeansthattheclientmightreceivesomeduplicatedmessages CLIENT_ACKNOWLEDGES:Withthis,theclientmanuallyacknowledges receivedmessagesusingtheacknowledgemethod ThemodescanbesetwhenyouretrieveJMSContextfromaconnectionfactory: JMSContextcontext= connectionFactory.createContext(JMSContext.CLIENT_ACKNOWLEDGE) Thefirstargumentisanintegerflagthatacceptsthevaluesmentionedpreviouslyalong withaSESSION_TRANSACTEDentry(whichisthestandardmodeforJTA-managed message-drivenbeans). UsingJMStointegratewithexternalsystems Atthebeginningofthischapter,wementionedthattheJCAadaptorhandlesthe communicationbetweentheapplicationserverandtheHornetQserver. Asamatteroffact,onepossiblewaytoperformEnterpriseApplicationIntegration (EAI)isviaJavaConnectorArchitecture(JCA),whichcanbeusedtodriveJMS’s inboundandoutboundconnections. Initially,Javaconnectorswereintendedtoaccesslegacytransactionserverson mainframesinasynchronousrequest/replymode,andthisishowthemajorityofthe connectorsworkedinthebeginning.Thestandardiscurrentlyevolvingtowardmore asynchronousandtwo-wayconnectivity;thisisexactlythecasewithJMS communication,whichisinherentlyasynchronous(butalsooffersthecapabilityof simulatingasynchronousrequest/responsemode).Inthenextsection,wewillshowyou howtouseaJavaResourceAdaptertoenablecommunicationbetweenJBoss’HornetQ MessagingsystemandastandaloneinstanceoftheApacheActiveMQbroker(whichcan beused,forinstance,byanon-JavaEEapplication). Tip JMS/JCAintegrationversuswebservices IfwearediscussingEAI,wecannothelpbuttalkaboutthedifferencebetweenweb services,whichisthedefactostandardforintegratingheterogeneoussystems. OneadvantageofusingtheJMS/JCAintegrationisthatitprovidessupportforresource adaptation,whichmapstheJavaEEsecurity,transaction,andcommunicationpoolingto thecorrespondingEIStechnology.Thismakesthistechnologyfairlyattractive,especially ifyouaretryingtoconnectsomeexisting,well-consolidated,andhomogeneoussystems (rememberthatifyouareusingJMSasthedriver,youareboundtoaJava-to-Java interaction). Ontheotherhand,ifyouareplanningtoconnectdifferentbusinesspartners(forexample, Javaand.NETapplications)orsimplybuildanewsystemfromscratchwithnoclear interactionsdefined,itwouldbebettertousewebservicesfortransportandconnection. WewilllearnmoreaboutwebservicesinChapter7,AddingWebServicestoYour Applications,whichshouldprovideyouwithquiteacompleteoverviewofyourEAI alternatives. Areal-worldexample–HornetQandActiveMQintegration Inthissection,wewillprovideanexamplescenario,whichincludesanexternal componentsuchastheApacheActiveMQ(Apache2.0opensourcelicensed)message brokerthatfullyimplementsJavaMessageService1.1(JMS).Anotherapplicationcould becommunicatingwithourticketingsystemusingthisbroker,butinoursample,wewill simulatetheexternalsystemusingtheActiveMQadministrationconsole. Inordertorunthisexample,wewillneedtopickuptheActiveMQresourceadapter, activemq-rar-5.9.0.rar,whichcanbedownloadedfromtheMavenrepositoryat http://repo1.maven.org/maven2/org/apache/activemq/activemq-rar/5.9.0/.Youwillalso needtheActiveMQbroker,whichyoucandownloadfrom https://activemq.apache.org/activemq-590-release.html.Simplyextractthebinary distributionandrunthe/apache-activemq-5.9.0/bin/activemq.batfiletostartthe broker. InstallingtheActiveMQresourceadapter Resourceadapters(.rar)canbedeployedusingeitherWildFlymanagementinstruments orbycopyingtheresourceadapterintothedeploymentsdirectoryforstandaloneservers. Beforedoingthis,weneedtoconfiguretheResourceadapterinyourserverconfiguration. ThiscanbedonebyaddingtheconfigurationtotheJCAsubsystemor(suggestedchoice) bycreatingaJCAdescriptoroftheexternalresource. JCAdescriptorscanbecreatedbyusinganutilitycontainedinJBoss’JCAimplementation namedIronJacamar(http://www.jboss.org/ironjacamar).WithinIronJacamar1.1orlater distributions(accessibleathttp://www.jboss.org/ironjacamar/downloads),youcanfinda resourceadapterinformationtool(rar-info.bat)thatcanbeusedtocreatetheresource adapterdeploymentdescriptorbygeneratingareportfilecontainingallthenecessary information. Therar-info.battoolcanbefoundinthedoc/asfolderofyourIronJacamar distribution.Solet’smovetothisfolder: $cddoc/as Nowissuethefollowingcommand,whichassumesthatyouhavesavedyourresource adapterinthe/usr/docfolder: rar-info.bat/usr/doc/activemq-rar-5.9.0.rar Tip Troubleshootingtherar-infoshell Therar-infocommandshellincludesasetoflibrariesthatareusedtoexecutethemain utilityclass.InordertoinspecttheJMSadapter,however,youneedtomanuallyeditthe shellfileandaddjboss-jms-api_2.0_spec-1.0.0.Finalandjboss-transactionapi_1.2_spec-1.0.0.Final.jartotheclasspath.ThoseJARfilesarecontainedinthe mainfolderunderJBOSS_HOME/modules/system/layers/base/javax/jms/api/and JBOSS_HOME/modules/system/layers/base/javax/transaction/api/.Simplyaddpaths forthemintherar-info.batfile(separatedbycharacter);forexample,refertothe following(assumingthejarsareinthesamedirectoryasrar-info.bat): java-classpathironjacamar-as.jar;....\lib\ironjacamar-commonspi.jar;....\lib\jboss-logging.jar;....\lib\jboss-commoncore.jar;....\lib\ironjacamar-specapi.jar;....\lib\jandex.jar;....\lib\ironjacamar-commonimpl.jar;....\lib\ironjacamar-common-api.jar;....\lib\ironjacamar-coreimpl.jar;....\lib\ironjacamar-core-api.jar;....\lib\ironjacamarvalidator.jar;....\lib\jandex.jar;....\lib\validationapi.jar;....\lib\hibernate-validator.jar;jboss-jms-api_2.0_spec1.0.0.Final.jar;jboss-transaction-api_1.2_spec-1.0.0.Final.jar org.jboss.jca.as.rarinfo.Main%* Thiswillgenerateafilecalledactivemq-rar-5.9.0-report.txt,whichwillprovideyou withtherequiredinformationtoconstructyourownJBoss’JCAconfigurationfilethat needstobenamedironjacamar.xml.Feelfreetocheckoutitscontents. Inthefollowingcode,youcanfindasampleironjacamar.xmlfilethatdefinesanew queue(java:jboss/activemq/queue/TicketQueue): <ironjacamar> <connection-definitions> <connection-definitionclassname=“org.apache.activemq.ra.ActiveMQManagedConnectionFactory”jndiname=“java:jboss/activemq/TopicConnectionFactory”poolname=“TopicConnectionFactory”> <pool> <min-pool-size>1</min-pool-size> <max-pool-size>200</max-pool-size> <prefill>false</prefill> </pool> <security> <application/> </security> <timeout> <blocking-timeout-millis>30000</blocking-timeout-millis> <idle-timeout-minutes>3</idle-timeout-minutes> </timeout> <validation> <background-validation>false</background-validation> <use-fast-fail>false</use-fast-fail> </validation> </connection-definition> <connection-definitionclassname=“org.apache.activemq.ra.ActiveMQManagedConnectionFactory”jndiname=“java:jboss/activemq/QueueConnectionFactory”poolname=“QueueConnectionFactory”> <pool> <min-pool-size>1</min-pool-size> <max-pool-size>200</max-pool-size> <prefill>false</prefill> </pool> <security> <application/> </security> <timeout> <blocking-timeout-millis>30000</blocking-timeout-millis> <idle-timeout-minutes>3</idle-timeout-minutes> </timeout> <validation> <background-validation>false</background-validation> <use-fast-fail>false</use-fast-fail> </validation> </connection-definition> </connection-definitions> <admin-objects> <admin-objectclass-name=“org.apache.activemq.command.ActiveMQQueue” jndi-name=“java:jboss/activemq/queue/TicketQueue”> <config-propertyname=“PhysicalName”> activemq/queue/TicketQueue </config-property> </admin-object> </admin-objects> </ironjacamar> Asyoucansee,thisfilecontainsthedefinitionofActiveMQconnectionfactoriesalong withthemappingofJMSadministrationobjects,whichwillbeimportedbytheresource adapter.Theironjacamar.xmlfileneedstobecopiedintotheMETA-INFfolderof activemq-rar-5.9.0.rar(youcanopentheRARfileusingthecompressedfilesmanager ofyourchoice,forexample,7-Zip). Tip Additionalconfigurationrequirementsoftheresourceadapter Alongwiththeironjacamar.xmlfile,thereisanotherconfigurationfilethatiscontained intheMETA-INFfolderofyouractivemq-rar-5.9.0.rarfile.Thera.xmlfileisthe standardJCAconfigurationfileanddescribestheresource-adapter-relatedattribute’stype anditsdeploymentproperties.We,however,donotneedtoalteritscontentsforourbasic sample. Nowthatwehavecompletedtheconfiguration,let’sdeploytheresourceadapter (activemq-rar-5.9.0.rar)intoourWildFlyandcheckthattheJCAfactoriesandobjects havebeencorrectlyboundtotheapplicationserver.Afterthedeployment,youshouldsee thefollowingsimilarmessagesinWildFly’sconsole: 19:52:51,521INFO[org.jboss.as.connector.deployment](MSCservicethread 1-5)JBAS010401:BoundJCAAdminObject [java:jboss/activemq/queue/TicketQueue] 19:52:51,521INFO[org.jboss.as.connector.deployment](MSCservicethread 1-5)JBAS010401:BoundJCAConnectionFactory [java:jboss/jms/TopicConnectionFactory] 19:52:51,521INFO[org.jboss.as.connector.deployment](MSCservicethread 1-8)JBAS010401:BoundJCAConnectionFactory [java:jboss/jms/ConnectionFactory] 19:52:51,542INFO[org.jboss.as.server](DeploymentScanner-threads-1) JBAS018559:Deployed“activemq-rar-5.9.0.rar”(runtime-name:“activemq- rar-5.9.0.rar”) ConsumingActiveMQmessages Welldone!Thehardestpartisdone.NowinordertoconsumeJMSmessagessentbythe ActiveMQbroker,wewilladda@ResourceAdapterannotationtoamessage-drivenbean. ThisMDBwillinterceptbookingsfromtheActiveMQbroker.Inordertobeabletouse the@ResourceAdapterannotation,wewillneedtoaddaJBoss-specificdependencytoour pom.xml: <dependency> <groupId>org.jboss.ejb3</groupId> <artifactId>jboss-ejb3-ext-api</artifactId> <version>2.1.0</version> <scope>provided</scope> </dependency> Ournewannotatedmessagebeanispresentedasfollows(notethattheproperty destinationTypeisthedestinationnow): @MessageDriven(name=“MDBService”,activationConfig={ @ActivationConfigProperty(propertyName=“destination”, propertyValue=“java:jboss/activemq/queue/TicketQueue”), @ActivationConfigProperty(propertyName=“destinationType”, propertyValue=“javax.jms.Queue”),} ) @ResourceAdapter(value=“activemq-rar-5.9.0.rar”) publicclassBookingQueueReceiverimplementsMessageListener{ @Inject privateLoggerlogger; @Override publicvoidonMessage(Messagemessage){ try{ finalStringtext=message.getBody(String.class); logger.info(“Receivedmessage”+text); }catch(JMSExceptionex){ logger.severe(ex.toString()); } } } Onceamessageisreceived,itiswrittentoaconsole.Thismeansthatitistimetodeploy ourapplication.IfyourActiveMQbrokerisrunning,youshouldseethefollowingsimilar messagesduringthedeploymentphase: 19:59:59,452INFO[org.apache.activemq.ra.ActiveMQEndpointWorker] (ServerServiceThreadPool—65)Starting 19:59:59,458INFO[org.apache.activemq.ra.ActiveMQEndpointWorker] (default-threads-1)Establishingconnectiontobroker [tcp://localhost:61616] 19:59:59,573INFO[javax.enterprise.resource.webcontainer.jsf.config](MSC servicethread1-5)InitializingMojarra2.2.5-jbossorg-320140128-1641for context‘/ticket-agency-jms’ 19:59:59,618INFO[org.apache.activemq.ra.ActiveMQEndpointWorker] (default-threads-1)Successfullyestablishedconnectiontobroker [tcp://localhost:61616] 20:00:00,053INFO[org.wildfly.extension.undertow](MSCservicethread15)JBAS017534:Registeredwebcontext:/ticket-agency-jms 20:00:00,081INFO[org.jboss.as.server](DeploymentScanner-threads-1) JBAS018559:Deployed“ticket-agency-jms.war”(runtime-name:“ticketagency-jms.war”) NowitistimetotestourconnectionusingtheActiveMQconsole,whichwillsenda messagestraighttotheActiveMQbroker.ActiveMQ5.9.0isequippedwithabundled hawt.ioconsole.Itisapluggablewebdashboardthatcanbeconfiguredtoadminister variousapplications.OneofthemisActiveMQ.And,oneofthebenefitsofusingthis consoleisthatyoucandeployitonalmostanyJVM-basedcontainer,includingWildFly. Checkouthttp://hawt.io/alongwiththeActiveMQplugin (http://hawt.io/plugins/activemq/)formoreinformation. Note FromVersion5.10.0,ActiveMQisnotprebundledwithhawt.ioanymore.Youcanprepare yourownhawt.ioconsolebyfollowingtheguidelinesavailableat http://hawt.io/getstarted/index.html;installingtheActiveMQplugin;or(whichwe stronglyrecommend)usingVersion5.9.0inyoursamples,whichisconveniently preconfigured. Gotohttp://localhost:8161/hawtio/andloginusingtheadmin/admincredentials: Afterthelogin,youshouldseethehawt.iowebconsole.Itisworthnotingthatitwas createdusingTwitterBootstrap,thesamefront-endframeworkthatweareusinginour application. Selectthefirsttab(ActiveMQ)andyoushouldseeatreethatrepresentsthecurrent configurationofthebroker.Findthenodelocalhost/Queue/.Whenyouexpandit,you shouldseethequeuewedefinedearlierinourresourceadapter: java_jboss/activemq/queue/TicketQueue.Afterselectingit,youcanchoosetheSend tabontheright-handside.Youshouldseeascreensimilartothefollowingone: EnterthedesiredmessageintothebigtextareainthecenterandclickontheSend Messagebutton.AfterswitchingtoourWildFlyconsole,weshouldseealogentrywith themessagewepassedtotheActiveMQbroker,asshowninthefollowingscreenshot: Congratulations!Ifyouhavegonesuccessfullythroughthisexample,youhavejust masteredareal-worldintegrationscenario.Tomakethesamplemorerealistic,youcould improvethemessagebeansothatitwouldbookticketsifthemessageweretocontainthe requiredinformation(forexample,message55,10wouldbookaseatwithID55for10$). Feelfreetoexperiment! Summary Inthischapter,wediscussedJBoss’message-orientedmiddlewarethatallowsyouto looselycoupleheterogeneoussystemstogetherwhiletypicallyprovidingreliability, transactions,andmanyotherfeatures. WesawhowtoconfigureJMSdestinationsusingthewebconsoleandcreatesome message-drivenbeans,whicharethestandardwaytoconsumemessagesfromwithinthe EJBcontainer. Wewillnowmoveontoanothercomponent,whichistypicallyusedforintegrating heterogeneoussystems—webservices. Chapter7.AddingWebServicestoYour Applications Inthepreviouschapter,wediscussedtheJavaMessagingServiceAPI,whichis commonlyusedtodeveloplooselycoupledapplicationsandacommonintegrationpattern forJava-to-Javasystems.Inthischapter,youwilllearnaboutwebservicesthatare definedbyW3Cassoftwaresystems,anddesignedtosupportinteroperablemachine-tomachineinteractionoveranetwork. Whatmakeswebservicesdifferentfromotherformsofdistributedcomputingisthat informationisexchangedusingonlysimpleandnonproprietaryprotocols.Thismeansthe servicescancommunicatewitheachotherregardlessoflocation,platform,or programminglanguage.Essentially,webservicesprotocolsprovideaplatformindependentwaytoperformRemoteProcedureCalls(RPCs). Thefocusofthischapterwillbeonthetwochiefwebservicesstandards,JAX-WS(JSR 224)andJAX-RS(JSR339),andhowtheyareimplementedinWildFly.Asyoucan imagine,thereisalotofgroundtocover,sowewillquicklygetourhandsdirtywiththe followingtopics: AshortintroductiontoSOAP-basedwebservices Creating,deploying,andusingtheJBossJAX-WSimplementation(ApacheCXF) AquickoverviewofRESTwebservices Howtocreate,deploy,anduseservicesusingtheJBossJAX-RSimplementation (RESTEasy) IntegratingJAR-RSwithanexternalnon-Javaapplication DevelopingSOAP-basedwebservices Asstated,webservicesarebasedontheexchangeofmessagesusingnonproprietary protocolmessages.Themessagesthemselvesarenotsufficienttodefinethewebservice platform.Weactuallyneedalistofstandardcomponents,includingthefollowing: Alanguageusedtodefinetheinterfacesprovidedbyawebserviceinamannerthat isnotdependentontheplatformonwhichitisrunningortheprogramminglanguage usedtoimplementit Acommonstandardformattoexchangemessagesbetweenwebserviceproviders andwebserviceconsumers Aregistrywithinwhichservicedefinitionscanbeplaced TheWebServiceDescriptionLanguage,alsoknownasWSDL, (http://www.w3.org/TR/wsdl)isthedefactostandardtoprovideadescriptionofaweb servicecontractexposedtoclients.Inparticular,aWSDLdocumentdescribesaweb serviceintermsoftheoperationsthatitprovides,andthedatatypesthateachoperation requiresasinputsandcanreturnintheformofresults. Communicationbetweentheserviceproviderandserviceconsumerhappensbymeansof XMLmessagesthatrelyontheSOAPspecification. AbasicSOAPmessageconsistsofanenvelopethatmaycontainanynumberofheaders andabody.ThesepartsaredelimitedbyXMLelementscalledenvelope,header,and body,whichbelongtoanamespacedefinedbytheSOAPspecification.Thefollowing figuredepictsthebasicstructureofaSOAPmessage: StrategiestobuildSOAP-basedwebservices Aswehavejustdiscussed,theservicedescriptionisprovidedbyacommonlyused documentinterfacenamedWSDLthatexposestheservicesasacollectionofnetworks, endpoints,andports,usingtheXMLformat. Youmaylogicallybeinclinedtothinkthatitisnecessarytostatethecorresponding programminginterfacesatthebeginningofthecontractofaserviceandthenproduce them. Actually,youcanfollowtwoapproachestodevelopyourSOAPwebservices: Top-down:ThisdevelopmentstrategyinvolvescreatingawebservicefromaWSDL file.Thetop-downapproachislikelytobeusedwhencreatingwebservicesfrom scratch.Itisthepreferredchoiceofpurewebserviceengineersbecauseitis business-driven,thatis,thecontractisdefinedbybusinesspeopleandsothesoftware isdesignedtofitthewebservicecontract. Bottom-up:ThisapproachrequirestheWSDLfiletobegeneratedbythe programminginterfaces.Itislikelytobeusedwhenwehaveexistingapplications thatwewanttoexposeaswebservices.Asthisapproachdoesnotrequireadeep knowledgeoftheWSDLsyntax,itistheeasiestchoiceifyouwanttoturnyourJava classesorEJBintowebservices. AstheaudienceofthisbookiscomposedmainlyofJavadeveloperswithlittleorno knowledgeofWSDLbasics,wewillfocusprimarilyonthebottom-upapproach. Designingtop-downwebservices,ontheotherhand,willrequireyoutointegratethe basicwebservicesnotionsprovidedwiththischapterwithacomprehensiveawarenessof theWSDLstandard. JBossSOAP-basedwebservicesstack AllJAX-WSfunctionalitiesprovidedontopofWildFlyarecurrentlyservedthrougha properintegrationoftheJBosswebservicesstackwithmostoftheApacheCXFproject. ApacheCXFisanopensourcewebserviceframeworkthatprovidesaneasy-to-use, standard-basedprogrammingmodeltodevelopbothSOAPandRESTwebservices.The integrationlayer(JBossWS-CXFinshorthereafter)allowsustoperformthefollowing: UsestandardwebservicesAPIs(includingJAX-WS)onaWildFlyApplication Server;thisisperformedinternallybyleveragingApacheCXF,withoutrequiringthe usertodealwithit LeverageApacheCXF’sadvancednativefeaturesontopofaWildFlyApplication Serverwithouttheneedfortheusertodealwithalltherequiredintegrationstepsto runtheapplicationinsuchacontainer Therefore,thefocusofthenextsectionwillbeondevelopingJAX-WSwebservicesusing thebuilt-inApacheCXFconfiguration.Ifyouwanttofurtherexpandyourknowledge aboutApacheCXF’snativefeatures,youcanrefertotheofficialdocumentationthatis availableathttp://cxf.apache.org/. AbrieflookattheJAXWSarchitecture WhenaSOAPmessagesentbythecliententersthewebserviceruntimeenvironment,itis capturedbyacomponentnamedserverendpointlistener,which,inturn,usesthe DispatchermoduletodelivertheSOAPmessagetothatservice. Atthispoint,theHTTPrequestisconvertedinternallyintoaSOAPmessage.Themessage contentisextractedfromthetransportprotocolandprocessedthroughthehandlerchain configuredforthewebservice. SOAPmessagehandlersareusedtointerceptSOAPmessagesastheymaketheirway fromtheclienttotheendpointserviceandviceversa.ThesehandlersinterceptSOAP messagesforboththerequestandresponseofthewebservice. ThenextstepisunmarshallingtheSOAPmessageintoJavaobjects.Thisprocessis governedbyWSDLtoJavaMappingandXMLtoJavaMapping.Theformerisperformed bytheJAX-WSengine,anditdetermineswhichendpointtoinvokefromtheSOAP message.Thelatter,performedbytheJAXBlibraries,deserializestheSOAPmessageso thatitisreadytoinvoketheendpointmethod. Finally,thedeserializedSOAPmessagereachestheactualwebserviceimplementation andthemethodisinvoked. Oncethecalliscompleted,theprocessisreversed.Thereturnvaluefromthewebservice methodismarshalledintoaSOAPresponsemessageusingJAX-WSWSDLtoJava mappingandJAXB2.0XMLtoJavamapping. Note TheJAXBprovidesafastandconvenientwaytobindXMLschemasandJava representations,makingiteasyforJavadeveloperstoincorporateXMLdataandprocess functionsinJavaapplications.Aspartofthisprocess,JAXBprovidesmethodsto unmarshalXMLinstancedocumentsintoJavacontenttrees,andthenmarshalJava contenttreesbackintoXMLinstancedocuments.JAXBalsoprovidesawaytogenerate XMLschemafromJavaobjects. Next,theoutboundmessageisprocessedbyhandlersbeforereturningittothedispatcher andendpointlistenerthatwilltransmitthemessageasanHTTPresponse. Thefollowingdiagramdescribeshowdataflowsfromawebserviceclienttoaweb serviceendpointandback: CodingSOAPwebserviceswithWildFly Inthefirstdeliverable,wewillshowhoweasilyyoucanturnaplainJavaclassintoaweb service.ThenewlycreatedservicewillthenbetestedusingasimpleEclipse-basedtesting GUI.ThesecondpartofthissectionwilldrawyourattentiontohowEJBscanbeexposed aswebserviceendpointsbyenhancingyourticketapplicationwithawebservice. DevelopingaPOJOwebservice Wewillstartdevelopingwebservices,usingourprojectfromChapter4,LearningContext andDependencyInjection(ticket-agency-cdi)asabase.WewillomitthecurrentJSFbasedweblayerfornow.YoucansafelyremovealloftheJSF-relatedclassesand configurations.Ifyouencounteranyproblems,rememberthatyou’llfindafullyworking projectinthecodeexamples,uponcompletionofthischapter. Ourfirstclasswillnotberelatedtoourticketapplication,butitwilljustdemonstratehow tocreateawebservicefromaPOJOclassnamedCalculatePowerWebService.Thisclass hasamethodnamedcalculatePower,whichreturnsthepowerofanargument,asshown inthefollowinghighlightedcode: packagecom.packtpub.wflydevelopment.chapter7.boundary; publicclassCalculatePowerWebService{ publicdoublecalculatePower(doublebase,doubleexponent){ returnMath.pow(base,exponent); } } Now,wewillturnthissimpleclassintoawebservicebyaddingthemandatory @WebServiceannotation: packagecom.packtpub.wflydevelopment.chapter7.webservice; importjavax.jws.WebMethod; importjavax.jws.WebParam; importjavax.jws.WebResult; importjavax.jws.WebService; importjavax.jws.soap.SOAPBinding; @WebService(targetNamespace=“http://www.packtpub.com/”, serviceName=“CalculatePowerService”) @SOAPBinding(style=SOAPBinding.Style.RPC) publicclassCalculatePowerWebService{ @WebMethod @WebResult(name=“result”) publicdoublecalculatePower(@WebParam(name=“base”)doublebase, @WebParam(name=“exponent”)double exponent){ returnMath.pow(base,exponent); } } Insidethe@WebServiceannotation,youcanspecifyadditionalelements,suchasthe targetNamespaceelementthatdeclaresthenamespaceusedfortheWSDLelements generatedbythewebservice.Ifyoudon’tspecifythiselement,thewebservicecontainer willusetheJavapackagenametogenerateadefaultXMLnamespace. YoucanalsousetheserviceNameelementtospecifytheservicename.Thename specifiedusingserviceNameisusedtogeneratethenameattributeintheserviceelement intheWSDLinterface.Ifyoudon’tspecifytheserviceNameelement,theserverwill generateitusingthedefaultvalue,whichisthebeanclassnameappendedwiththe service. Inthenextrow,westatethatthewebserviceisofthetypeRemoteProcedureCallusing the@javax.jws.SOAPBindingannotation.ThepossiblevaluesareDOCUMENTandRPC,the firstonebeingthedefaultvalue. Note ThechoicebetweentheRPCandDocumentstyleboilsdowntothedifferentwayswecan constructservicesusingthesetwostyles.ThebodyofanRPC-styleSOAPmessageis constructedinaspecificway,whichisdefinedintheSOAPstandard.Thisisbuiltonthe assumptionthatyouwanttocallthewebservicejustlikeyouwouldcallanormal functionormethodthatispartofyourapplicationcode. Therefore,theRPCismoretightlycoupledbecauseifyoumakeanychangesinthe messagestructure,you’llneedtochangealltheclientsandserversprocessingthiskindof message. Adocument-stylewebservice,ontheotherhand,containsnorestrictionsforhowthe SOAPbodymustbeconstructed.ItallowsyoutoincludewhateverXMLdatayouwant andalsoaschemaforthisXML.Therefore,thedocumentstyleisprobablymoreflexible, buttheefforttoimplementthewebserviceandclientsmaybeslightlymore. Intheend,thelikelihoodofchangeisafactorthatonehastoconsiderwhenchoosing whethertouseRPC-orDocument-stylewebservices. Attachingthe@WebMethodattributetoapublicmethodindicatesthatyouwantthemethod exposedaspartofthewebservice. The@WebParamannotationisusedtospecifytheparameter’snamethatneedstobe exhibitedintheWSDL.YoushouldalwaysconsiderusingaWebParamannotation, especiallywhenusingmultipleparameters,otherwisetheWSDLwillusethedefault argumentparameter(inthiscase,arg0),whichismeaninglessforwebserviceconsumers. The@WebResultannotationisquitesimilarto@WebParaminthesensethatitcanbeusedto specifythenameofthevaluereturnedbytheWSDL. Yourwebserviceisnowcomplete.Inordertodeployyourwebservice,runthefollowing Mavengoal,whichwillpackageanddeployyourwebservicetoyourrunningWildFly instance: mvnpackagewildfly:deploy WildFlywillprovideaminimaloutputontheconsole;thiswillinformyouthattheweb serviceprojecthasbeendeployedandtheWSDLfilehasbeengenerated: 14:25:37,195INFO[org.jboss.weld.deployer](MSCservicethread1-11) JBAS016005:StartingServicesforCDIdeployment:ticket-agency-ws.war 14:25:37,198INFO[org.jboss.ws.cxf.metadata](MSCservicethread1-11) JBWS024061:Addingserviceendpointmetadata: id=com.packtpub.wflydevelopment.chapter7.boundary.CalculatePowerWebService address=http://localhost:8080/ticket-agency-ws/CalculatePowerService implementor=com.packtpub.wflydevelopment.chapter7.boundary.CalculatePowerWebServi serviceName={http://www.packtpub.com/}CalculatePowerService portName={http://www.packtpub.com/}CalculatePowerWebServicePort annotationWsdlLocation=null wsdlLocationOverride=null mtomEnabled=false Fromtheshortlog,youcanpickupsomeusefulinformation.Forexample,thefirstline statesthatthewebservicehasbeenboundintheendpointregistryas {http://www.packtpub.com/}CalculatePowerService.Nextistheinformationaboutthe webcontextpath,which,bydefault,hasthesamenameasyourproject,thatis,ticketagency-ws.Thelastpieceofinformationisaboutthewebserviceaddress,whichis http://localhost:8080/ticket-agency-ws/CalculatePowerService.Byappendingthe ?wsdlsuffixtotheendoftheaddress,youcaninspectthewebservicecontract. Note ThedatadirectorycontainsaversionedlistofallthegeneratedWSDLs.So,youmight findtheentirehistoryofyourwebservicespublishedbyticket-agency-wsin JBOSS_HOME/standalone/data/wsdl/ticket-agency-ws.war. Inspectingthewebservicefromtheconsole Youcaninspectthewebservicessubsystembymovingtothewebadminconsoleand navigatingtoRuntime|Status|Subsystems|WebServices. Here,youcangathersomeusefulinformationabouttheservicesdeployed.Infact,the mostusefuloptionisthelistofendpointcontractsavailable,whichisneededwhen developingourclients.Thefollowingscreenshotshowsaviewofthewebservice endpointsfromtheconsole: Particularly,inthelowerpartofthescreen,youcanreadthewebserviceendpointaddress thatbearsthewebapplicationcontextnameandregisterednameforthewebservice.In ourcase,itishttp://localhost:8080/ticket-agency-ws/CalculatePowerService? wsdl. Testingoursimplewebservice Sinceourfirstwebserviceisnotyetconnectedtoourticketingsystem,wewillusean externalclientapplicationtotestourwebservice.Oneofthebesttoolstotestweb servicesisSoapUI. SoapUIisafree,opensource,cross-platformfunctionaltestingsolutionwithaneasy-tousegraphicalinterfaceandenterprise-classfeatures.Thistoolallowsyoutocreateand executeautomated,functional,regression,compliance,andloadtestseasilyandrapidly. SoapUIisalsoavailableasanEclipseplugin. Here,wewillusetheSoapUIstandaloneapplication.RunitandcreateanewSOAP projectprovidingtheURLtotheserviceWSDL,asshowninthefollowingscreenshot: Afterthis,you’llseeaviewcontainingafewwindows.Themostimportantonesshowthe requestlogsandtheprojectviewinthenavigatorwindow,asshowninthefollowing screenshot: Asyoucansee,yourserviceoperationshavebeenautomaticallydiscovered.Double-click ontheRequest1treeelement;theSoapUIrequestwindowwillappearwhereyoucan enterthenamedparameters.Enterthetwoargumentsforthewebservice,asshowninthe followingscreenshot: ClickontheSubmitbuttononthetoolbarandchecktheresultintheSOAPresponse window: EJB3StatelessSessionBean(SLSB)webservices TheJAX-WSprogrammingmodelsupportsthesamesetofannotationsonEJB3Stateless SessionBeanasitdoesonPOJOendpoints.Nowthatwealreadyhavesomewebservice muscle,wewillengineeroneoftheexamplesintroducedinthisbook. OurmainwebserviceclasswillbenamedDefaultTicketWebServiceandwillusesome ofthecoreclassesthatwedescribedinChapter3,IntroducingJavaEE7–EJBs,suchas TheatreBox,whichwillkeepinmemorytheticketbookingsandtheSeatclassasthe model.ThebusinessmethodsofourwebservicewillbedescribedbyaServiceEndpoint Interface(SEI)namedTicketWebService: packagecom.packtpub.wflydevelopment.chapter7.boundary; importjavax.jws.WebService; importjava.util.List; @WebService publicinterfaceTicketWebService{ List<SeatDto>getSeats(); voidbookSeat(intseatId); } Note Writingtheserviceinterfaceisalwaysagoodpracticeasitgivesaproperclient-sideview ofourServicemethods.Theimplementationclasscanthenimplementthemethods definedintheinterface. Wewillnowimplementtheinterfacebyprovidingthebusinesslogictotheinterface methodsintheDefaultTicketWebServiceclass: packagecom.packtpub.wflydevelopment.chapter7.boundary; importjavax.inject.Inject; importjavax.jws.WebMethod; importjavax.jws.WebParam; importjavax.jws.WebResult; importjavax.jws.WebService; importjava.io.Serializable; importjava.util.List; importjava.util.stream.Collectors; @WebService(targetNamespace=“http://www.packtpub.com/”,serviceName= “TicketWebService”) publicclassDefaultTicketWebServiceimplementsTicketWebService, Serializable{ @Inject privateTheatreBoxtheatreBox; @WebMethod @WebResult(name=“listSeats”) publicList<SeatDto>getSeats(){ returntheatreBox.getSeats() .stream() .map(SeatDto::fromSeat) .collect(Collectors.toList()); } @WebMethod publicvoidbookSeat(@WebParam(name=“seatId”)intseatId){ theatreBox.buyTicket(seatId); } } Asyoucansee,theimplementationclasscontainsthegetSeatsmethod,whichreturnsthe listofseatsthatareself-generatedwhentheTheatreBoxobjectisinitialized.The bookSeatmethodwillbeabletobookseatsforyourwebserviceclientsaswell. Nowdeployyourwebserviceandverifyontheconsolethatithasbeencorrectly registered: 00:43:12,033INFO[org.jboss.ws.cxf.metadata](MSCservicethread1-13) JBWS024061:Addingserviceendpointmetadata: id=com.packtpub.wflydevelopment.chapter7.boundary.DefaultTicketWebService address=http://localhost:8080/ticket-agency-ws/TicketWebService implementor=com.packtpub.wflydevelopment.chapter7.boundary.DefaultTicketWebServic serviceName={http://www.packtpub.com/}TicketWebService portName={http://www.packtpub.com/}DefaultTicketWebServicePort annotationWsdlLocation=null wsdlLocationOverride=null mtomEnabled=false Developingawebserviceconsumer ThewebserviceconsumeroftheTicketWebServiceclasswillbecodedusingthe standardJavaSEclasses.WewanttoshowherehowtousethesestandardAPIs.Forthis reason,youcanjustaddaclassnamedTicketWebServiceTestApplicationtoyour currentoraseparateprojectinthepackage com.packtpub.wflydevelopment.chapter7.webservice: packagecom.packtpub.wflydevelopment.chapter7.webservice; importcom.packtpub.wflydevelopment.chapter7.boundary.SeatDto; importcom.packtpub.wflydevelopment.chapter7.boundary.TicketWebService; importjavax.xml.namespace.QName; importjavax.xml.ws.Service; importjava.net.MalformedURLException; importjava.net.URL; importjava.util.Collection; importjava.util.List; importjava.util.logging.Logger; publicclassTicketWebServiceTestApplication{ privatestaticfinalLoggerlogger= Logger.getLogger(TicketWebServiceTestApplication.class.getName()); publicstaticvoidmain(String[]args)throwsMalformedURLException{ finalintseatId=1; logger.info(“TESTSOAPWSService”); finalURLwsdlURL=newURL(“http://localhost:8080/ticket-agencyws/TicketWebService?wsdl”); finalQNameSERVICE_NAME=newQName(“http://www.packtpub.com/”, “TicketWebService”); finalServiceservice=Service.create(wsdlURL,SERVICE_NAME); finalTicketWebServiceinfoService= service.getPort(TicketWebService.class); logger.info(“GottheService:”+infoService); infoService.bookSeat(seatId); logger.info(“TicketBookedwithJAX-WSService”); finalList<SeatDto>list=infoService.getSeats(); dumpSeatList(list); } privatestaticvoiddumpSeatList(Collection<SeatDto>list){ logger.info(“=================AvailableTicketList ================”); list.stream().forEach(seat->logger.info(seat.toString())); } } TheserviceWSDLURLandnameareneededforretrievaloftheServiceobject.Finally, thegetPortmethodwillreturnaproxytoyourwebservicethatcanbeusedtotesttwo basicoperations:bookingaseatandcheckingfromtheSeatlistiftheseathasactually beenreserved. ThissmallstandaloneclasshasshownhowitispossibletouseSOAP-basedservicesfrom theclient-sideperspective. Themostinterestingpart,however,isatthebottomoftheMavenoutput,wherethe Ticketlistisdumpedafterbookingoneseat,asdepictedinthefollowingcommandline: apr01,20141:08:44AM com.packtpub.wflydevelopment.chapter7.webservice.TicketWebServiceTestApplication main INFO:TESTSOAPWSService apr01,20141:08:44AM com.packtpub.wflydevelopment.chapter7.webservice.TicketWebServiceTestApplication main INFO:GottheService:JAX-WSRI2.2.9-b130926.1035svnrevision#8c29a9a53251ff741fca1664a8221dc876b2eac8:Stubfor http://localhost:8080/ticket-agency-ws/TicketWebService apr01,20141:08:44AM com.packtpub.wflydevelopment.chapter7.webservice.TicketWebServiceTestApplication main INFO:TicketBookedwithJAX-WSService apr01,20141:08:44AM com.packtpub.wflydevelopment.chapter7.webservice.TicketWebServiceTestApplication dumpSeatList INFO:=================AvailableTicketList================ apr01,20141:08:44AM com.packtpub.wflydevelopment.chapter7.webservice.TicketWebServiceTestApplication lambda$dumpSeatList$0 INFO:SeatDto[id=1,name=Stalls,price=40,booked=true] apr01,20141:08:44AM com.packtpub.wflydevelopment.chapter7.webservice.TicketWebServiceTestApplication lambda$dumpSeatList$0 INFO:SeatDto[id=2,name=Stalls,price=40,booked=false] … DevelopingREST-basedwebservices JAX-RS2.0(JSR-339canbefoundathttps://jcp.org/en/jsr/detail?id=339)isaJCP specificationthatprovidesaJavaAPIforRESTfulwebservicesintheHTTPprotocol.It isamajorrefreshfromtheoldVersion1.1.SomeofthenewfeaturesaretheclientAPI, HATEOASsupport,andasynchronouscalls. Intheirsimplestform,RESTfulwebservicesarenetworkedapplicationsthatmanipulate thestateofsystemresources.Inthiscontext,resourcemanipulationmeansresource creation,retrieval,updatation,anddeletion(CRUD).However,RESTfulwebservicesare notlimitedtojustthesefourbasicdatamanipulationconcepts.Onthecontrary,RESTful webservicescanexecutelogicattheserverlevelbutrememberthateveryresultmustbea resourcerepresentationofthedomain. ThemaindifferencewithSOAPwebservicesisthatRESTasksdeveloperstouseHTTP methodsexplicitlyandinawaythat’sconsistentwiththeprotocoldefinition.Thisbasic RESTdesignprincipleestablishesaone-to-onemappingbetweenCRUDoperationsand HTTPmethods. Therefore,withthedelineatedrolesforresourcesandrepresentations,wecannowmap ourCRUDactionstotheHTTPmethodsPOST,GET,PUT,andDELETEasfollows: Action HTTPprotocolequivalent RETRIEVE GET CREATE POST UPDATE PUT DELETE DELETE AccessingRESTresources Aswesaid,RESTresourcescanbeaccessedusingactionsthatmapanequivalentHTTP request.InordertosimplifythedevelopmentofRESTapplications,youcanusesimple annotationstomapyouractions;forexample,inordertoretrievesomedatafromyour application,youcanusesomethingsimilartothefollowing: @Path(“/users”) publicclassUserResource{ @GET publicStringhandleGETRequest(){…} @POST publicStringhandlePOSTRequest(Stringpayload){…} } Thefirstannotation,@Path,inourexampleisusedtospecifytheURIthatisassignedto thiswebservice.Subsequentmethodshavetheirspecific@Pathannotationsothatyoucan provideadifferentresponseaccordingtotheURIrequested. Then,wehavean@GETannotationthatmapsanHTTPGETrequestandan@POST annotationthathandlesanHTTPPOSTrequest.So,inthisexample,ifweweretorequest forawebapplicationboundtotheexamplewebcontext,anHTTPGETrequesttotheURL http://host/example/userswouldtriggerthehandleGETRequestmethod;ontheother hand,anHTTPPOSTrequesttothesameURLwouldconverselyinvokethe handlePOSTRequestmethod. JBossRESTwebservices HavingunderstoodthebasicsofRESTservices,let’sseehowwecandevelopaRESTful webserviceusingWildFly.Theapplicationserverincludesanout-of-the-boxRESTEasy librarythatisaportableimplementationoftheJSR-339specification.RESTEasycanrun inanyservletcontainer;however,itisperfectlyintegratedwithWildFly,thusmakingthe userexperiencenicerinthatenvironment. Besidestheserver-sidespecification,inthepast,RESTEasyhasbeeninnovativein bringingJAX-RStotheclientthroughtheRESTEasyJAX-RSClientFramework. However,thelatestversionoftheJAX-RSspecificationcomeswithaclientAPI,which wecanuseineveryJAX-RSimplementation. ActivatingJAX-RS RESTEasyisbundledwithWildFly,soyouneedverylittleefforttogetstarted.Youhave twochoices.Thefirstoneistousethe@ApplicationPathannotationinaclassthat extendsjavax.ws.rs.core.Application: @ApplicationPath(“/rest”) publicclassJaxRsActivatorextendsApplication{ } Thesecondchoiceislesspopularandusedtoconfiguretheapplicationusingaweb.xml file: <?xmlversion=“1.0”encoding=“UTF-8”?> <web-appxmlns=“http://java.sun.com/xml/ns/j2ee” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd”version=“3.0”> <servlet> <servlet-name>javax.ws.rs.core.Application</servlet-name> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>javax.ws.rs.core.Application</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app> Thissimplymeansthatifweweretodeployourformerexample,theHTTPGETmethod, http://host/example/rest/userswouldtriggerourgetUserbusinessmethod,whilethe sameURLwillplacearequestthroughthehandlePOSTRequestmethodusingaPOST request. AddingRESTtoourticketexample Withalltheconfigurationsinplace,wecannowaddasimpleRESTwebservicetoour TicketWebServiceproject,whichwillprovidethesamefunctionalitiesasourSOAP webservice. SoaddanewclasstoyourprojectandnameitSeatsResource.Thecodeforthisisas follows: packagecom.packtpub.wflydevelopment.chapter7.boundary; @Path(“/seat”) @Produces(MediaType.APPLICATION_JSON) @RequestScoped publicclassSeatsResource{ @Inject privateTheatreBookertheatreBooker; @Inject privateTheatreBoxtheatreBox; @GET publicCollection<SeatDto>getSeatList(){ returntheatreBox.getSeats() .stream() .map(SeatDto::fromSeat) .collect(Collectors.toList()); } @POST @Path(“/{id}”) publicResponsebookPlace(@PathParam(“id”)intid){ try{ theatreBooker.bookSeat(id); returnResponse.ok(SeatDto.fromSeat(theatreBox.getSeat(id))) .build(); }catch(Exceptione){ finalEntity<String>errorMessage=Entity .json(e.getMessage()); returnResponse.status(Response.Status.BAD_REQUEST) .entity(errorMessage).build(); } } } Ifyouhaveunderstoodourearliersectionwell,thiscodewillbealmostintuitivetoyou. Wehaveincludedtwomethodshere,justliketheSOAPalterego;theformeroneis namedgetSeatList,whichisboundtoanHTTPGETrequestandproducesthelistof Seats.ThelistisreturnedusingaJSONrepresentationthatisprettycommonwhen returningJavaobjectstotheclient. Note ThegrammarforJSONobjectsissimpleandrequiresthegroupingofthedatadefinition anddatavalues;itisasfollows: Elementsareenclosedwithincurlybrackets({and}) Valuesofelementscomeinpairswiththestructureofname:valueandarecomma separated Arraysareenclosedwithinsquarebrackets([and]) That’sallthereistoit(forthefullJSONgrammardescription,visithttp://www.json.org/). ThesecondmethodincludedinthisclassisbookPlace,whichwillbeusedtoinvokethe correspondingbookSeatclassofourEJB.Thismethod,ontheotherhand,isboundtothe followingHTTPPOSTmethod: @POST @Path(“/{id}”) publicResponsebookPlace(@PathParam(“id”)intid) YoumightbethinkingthatthisPathexpressionseemsabitweird,butallitdoesismapa URIparameter(includedinthePathexpression)toamethodparameter.Inshort,the parameterthatisincludedintheURLwillbepassedtothemethodintheIDvariable. ThepreviousmethodalsoreturnsaJSON-formattedstringthatisencodedanddecoded usingJackson(bydefault,itispossibletocreateyourownmessagebodyproviders!),a librarythattransformsPOJOstoJSON(andviceversa). Beforeweproceed,weneedtoextendoursamplewithanewresourceaccount,whichwill allowustocheckthecashstatusandoptionallyresetit: packagecom.packtpub.wflydevelopment.chapter7.boundary; @Path(“/account”) @Produces(MediaType.APPLICATION_JSON) @RequestScoped publicclassAccountResource{ @Inject privateTheatreBookertheatreBooker; @GET publicAccountDtogetAccount(){ returnAccountDto .fromAccount(theatreBooker.getCurrentAccount()); } @POST publicResponserenew(){ theatreBooker.createCustomer(); returnResponse .ok(AccountDto.fromAccount(theatreBooker.getCurrentAccount())) .build(); } } Theaccountrepresentationisavailable,asshowninthefollowingcode: packagecom.packtpub.wflydevelopment.chapter7.entity; publicclassAccount{ privatefinalintbalance; publicAccount(intinitialBalance){ this.balance=initialBalance; } publicAccountcharge(intamount){ finalintnewBalance=balance-amount; if(newBalance<0){ thrownewIllegalArgumentException(“Debitvalueonaccount!”); } returnnewAccount(newBalance); } publicintgetBalance(){ returnbalance; } @Override publicStringtoString(){ return“Account[balance=”+balance+“]”; } } ThelaststepistoupdateourTheatreBookerclasstouseournewaccountrepresentation: privateAccountcurrentAccount; @PostConstruct publicvoidcreateCustomer(){ currentAccount=newAccount(100); } publicvoidbookSeat(intseatId){ logger.info(“Bookingseat”+seatId); finalintseatPrice=theatreBox.getSeatPrice(seatId); if(seatPrice>currentAccount.getBalance()){ thrownewIllegalArgumentException(“Notenoughmoney!”); } theatreBox.buyTicket(seatId); currentAccount=currentAccount.charge(seatPrice); logger.info(“Seatbooked.”); } publicAccountgetCurrentAccount(){ returncurrentAccount; } Note ThenewestversionofJAX-RSalsosupportsserver-sideasynchronousresponses.Thanks tothe@SuspendedannotationandtheAsyncResponseclass,youcanuseaseparate (possiblydelayed)threadtohandlearequestcall. Addingfilters JAX-RSallowsustodefinefiltersandinterceptorsforboththeclientandserver.They allowthedevelopertoaddresscross-cuttingconcerns,suchassecurity,auditing,or compression.Basically,youcantreatfiltersandinterceptorsasextensionpoints. Filtersareusedmainlyonheadersofrequestsandresponses.Forexample,youcanblock arequestbasedonitsheaderfieldsorlogonlyfailedrequests.Onthecontrary, interceptorsdealwithmessagebodies,forexample,youcansignorcompressthe messages.Interceptorsalsocomeintwoflavors:oneforreading(theyareexecutedwhen amessageistranslatedintoaPOJO,forexampleJSONtoSeatDto)andoneforwriting (theyareusedforPOJOtomessagetranslation). Wecanaddasimpleserver-sideloggingfiltertoourapplicationbycreatingthefollowing class: packagecom.packtpub.wflydevelopment.chapter7.controller; importjava.io.IOException; importjava.util.logging.Logger; importjavax.inject.Inject; importjavax.ws.rs.container.ContainerRequestContext; importjavax.ws.rs.container.ContainerRequestFilter; importjavax.ws.rs.container.ContainerResponseContext; importjavax.ws.rs.container.ContainerResponseFilter; importjavax.ws.rs.ext.Provider; @Provider publicclassLoggingRestFilterimplementsContainerRequestFilter, ContainerResponseFilter{ @Inject privateLoggerlogger; @Override publicvoidfilter(ContainerRequestContextrequestContext, ContainerResponseContextresponseContext) throwsIOException{ logger.info(responseContext.getStatusInfo().toString()); } @Override publicvoidfilter(ContainerRequestContextrequestContext)throws IOException{ logger.info(requestContext.getMethod()+”on”+ requestContext.getUriInfo().getPath()); } } Asyoucansee,weimplementtwoprettystraightforwardinterfaces: ContainerRequestFilterandContainerResponseFilter.Wesimplylogsome informationabouttheHTTPrequestandresponse.Toactivatethefilter,weusethe @Providerannotation;withoutadditionalconfiguration,thefilterwillworkforevery RESTresourceinourapplication.Additionally,ifwewouldliketorejectarequestinthe filter,thereisarequestContext.abortWithmethod. Theclientsidehastwocorrespondinginterfaces:ClientRequestFilterand ClientResponseFilter.Theimplementations,however,mustberegisteredmanually. NowtheRESTserviceiscompleteandwecanstartdeployingitintheusualway: mvnpackagewildfly:deploy Ifyoufollowedallthestepssofar,thehttp://localhost:8080/ticket-agencyws/rest/seatGETmethodissuedbyyourbrowsershouldprintoutthelistofavailable seats: [{“id”:0,“name”:“Stalls”,“price”:40,“booked”:false}, {“id”:1,“name”:“Stalls”,“price”:40,“booked”:false}, {“id”:2,“name”:“Stalls”,“price”:40,“booked”:false}, {“id”:3,“name”:“Stalls”,“price”:40,“booked”:false}, {“id”:4,“name”:“Stalls”,“price”:40,“booked”:false}, …… Goingtohttp://localhost:8080/ticket-agency-ws/rest/accountwillresultin: {“balance”:100} Youshouldalsoseesomelogstatementsfromourfilterintheconsole,forinstance: 19:52:45,906INFO [com.packtpub.wflydevelopment.chapter7.controller.LoggingRestFilter] (defaulttask-10)GETon/seat 19:52:45,909INFO [com.packtpub.wflydevelopment.chapter7.controller.LoggingRestFilter] (defaulttask-10)OK 20:29:04,275INFO [com.packtpub.wflydevelopment.chapter7.controller.LoggingRestFilter] (defaulttask-14)GETon/account 20:29:04,313INFO [com.packtpub.wflydevelopment.chapter7.controller.LoggingRestFilter] (defaulttask-14)OK ConsumingourRESTservice ConnectingtoaRESTfulwebservicetakesnomoreworkthandirectlyconnectingtothe servicethroughanHTTPconnection.Forthisreason,youcanuseplentyofAPIstoaccess yourRESTservices,suchastheJDKURLConnectionclassorJakartaCommons HttpClientAPI,sincewehaveastandardizedclientavailableinJAX-RS. IfyouwanttoretrievethelistofSeatsfromyourRESTservice,yourcodeshouldlook likethis: Clientrestclient=ClientBuilder.newClient(); WebTargetseatResource=restclient.target(APPLICATION_URL+“seat”); Collection<SeatDto>seats=seatResource.request().get(new GenericType<Collection<SeatDto>>(){}); ThepreviouscodewillsimplyperformaGETactiontotheRESTservicethatisdeployed aspartoftheticket-agency-wswebapplication.RESTEasy(usingJackson)will transformtheJSONobjects. Thefollowingstandalonesamplewillgetthedatafromtheaccountandseatresourcesand attempttobookalloftheavailableseats: publicclassRestServiceTestApplication{ privatestaticfinalStringAPPLICATION_URL= “http://localhost:8080/ticket-agency-ws/rest/”; privateWebTargetaccountResource; privateWebTargetseatResource; publicstaticvoidmain(String[]args){ newRestServiceTestApplication().runSample(); } publicRestServiceTestApplication(){ Clientrestclient=ClientBuilder.newClient(); accountResource=restclient.target(APPLICATION_URL+“account”); seatResource=restclient.target(APPLICATION_URL+“seat”); } publicvoidrunSample(){ printAccountStatusFromServer(); System.out.println(“===Currentstatus:“); Collection<SeatDto>seats=getSeatsFromServer(); printSeats(seats); System.out.println(“===Booking:“); bookSeats(seats); System.out.println(“===Statusafterbooking:“); Collection<SeatDto>bookedSeats=getSeatsFromServer(); printSeats(bookedSeats); printAccountStatusFromServer(); } privatevoidprintAccountStatusFromServer(){ AccountDtoaccount= accountResource.request().get(AccountDto.class); System.out.println(account); } privateCollection<SeatDto>getSeatsFromServer(){ returnseatResource.request().get(new GenericType<Collection<SeatDto>>(){}); } privatevoidprintSeats(Collection<SeatDto>seats){ seats.forEach(System.out::println); } privatevoidbookSeats(Collection<SeatDto>seats){ for(SeatDtoseat:seats){ try{ StringidOfSeat=Integer.toString(seat.getId()); seatResource.path(idOfSeat).request().post(Entity.json(””), String.class); System.out.println(seat+”booked”); }catch(WebApplicationExceptione){ Responseresponse=e.getResponse(); StatusTypestatusInfo=response.getStatusInfo(); System.out.println(seat+”notbooked(”+ statusInfo.getReasonPhrase()+“):”response.readEntity(JsonObject.class). getString(“entity”)); } } } } Inthehighlightedfragments,youcanseetheRESTcallsusedtoretrievethedataand bookingseats.OurpostcallrequiresanIDtobespecified;wedothatbyusingthepath methodoftherequestbuilder.Itisalsopossibletomakethecallasynchronously,using theasyncmethodandaFutureobject: Future<Collection<SeatDto>>future=seatResource.request() .async().get(newGenericType<Collection<SeatDto>>(){}); WecanusethenewCompletableFutureclassfromJava8tobenotifiedaboutthe completionofarequest: CompletableFuture.<Collection<SeatDto>>supplyAsync(()->{ try{ returnfuture.get(); }catch(Exceptione){ e.printStackTrace(); thrownewIllegalArgumentException(e); } }).thenAccept(seats->seats.forEach(System.out::println)); Afterreceivingthedata,wesimplyprintitout.Anotheroptionistosimplycreatean InvocationCallbackclassandpassitasasecondargumenttothegetmethod. Compilingourticketexample OursamplecanresideinaseparateMavenmoduleoryoucanleaveitwiththeserver content(althoughitisnotagoodpractice).Inordertocompileourclientprojectwiththe RESTwebservice,weneedtoimporttheJAX-RSAPIthatisincludedintheapplication serverlibraries.Wewillneedthefollowingdependenciesinourstandaloneapplication: <properties> … <version.resteasy-client>3.0.6.Final</version.resteasy-client> </properties> <dependencies> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-client</artifactId> <version>${version.resteasy-client}</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-json-p-provider</artifactId> <version>${version.resteasy-client}</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson-provider</artifactId> <version>${version.resteasy-client}</version> </dependency> <dependency> <groupId>com.packtpub.wflydevelopment.chapter7</groupId> <artifactId>ticket-agency-ws</artifactId> <version>1.0</version> </dependency> </dependencies> IfyouhaveanyproblemswiththecreationofthePOMfile,youcanlookitupinthe samplesthataredistributedwiththisbook. Nowsimplyrunyourapplication,andyoushouldseesomethingsimilartothefollowing consoleoutput: AccountDto[balance=100] ===Currentstatus: SeatDto[id=1,name=Stalls,price=40,booked=false] SeatDto[id=2,name=Stalls,price=40,booked=false] SeatDto[id=3,name=Stalls,price=40,booked=false] SeatDto[id=4,name=Stalls,price=40,booked=false] SeatDto[id=5,name=Stalls,price=40,booked=false] SeatDto[id=6,name=Circle,price=20,booked=false] SeatDto[id=7,name=Circle,price=20,booked=false] … AddingAngularJS OursamplesfortheRESTintegrationarenotveryspectacular.However,becausewe exposethefunctionalityofourapplicationviaaRESTAPI,itiseasytocreateanon-Java GUI,whichcanbeusedtocontroltheapplication. TocreateaGUIthatusesonlytheRESTAPItocommunicatewithourJavabackend,we willuseapopularJavaScriptframework:AngularJS(http://angularjs.org/).Wewon’tget intotoomuchdetailoftheJavaScriptcode.Themostinterestingpartforusistheusageof ourRESTAPI,whichwecurrentlyconsumeonlyinaJavaapplication. AsseeninChapter5,CombiningPersistencewithCDI,wewilluseWebJars.Thistime, apartfromBootstrap,weneedtheAngularJS(preferablyinVersion3.x)andAngularUI Bootstrappackage(http://angular-ui.github.io/bootstrap/): <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>angularjs</artifactId> <version>1.3.0-rc.1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>angular-ui-bootstrap</artifactId> <version>0.11.0-2</version> </dependency> Note Rememberthatallthefilesthatarerequiredtorunthissampleareavailablewiththecode attachedtothisbook. Wewillneedanindex.htmlfiletostartourworkandanemptyscriptsdirectorytostore ourlogic.Ourdirectorystructureshouldcurrentlylooklikethis: Intheindex.htmlfile,weneedtoaddalltherequiredlibrariesalongwithourwellknownBootstrapstructure: <!doctypehtml> <htmllang=“en”ng-app=“ticketApp”> <head> <metacharset=“utf-8”> <title>TicketService</title> <linkrel=“stylesheet” href=““webjars/bootstrap/3.2.0/css/bootstrap.css”> <linkrel=“stylesheet”href=““webjars/bootstrap/3.2.0/css/bootstraptheme.css”> <style> body{ padding-top:60px; } </style> </head> <body> <divclass=“navbarnavbar-inversenavbar-fixed-top”role=“navigation”> </div> <divclass=“container”ng-controller=“SeatCtrl”> <footer> <pclass=“text-muted”>©PacktPublishing2014</p> </footer> </div> <scriptsrc=“webjars/angularjs/1.3.0-rc.1/angular.js”></script> <scriptsrc=“webjars/angularjs/1.3.0-rc.1/angular-resource.js”></script> <scriptsrc=“webjars/angularjs/1.3.0-rc.1/angular-route.js”></script> <scriptsrc=“webjars/angular-ui-bootstrap/0.11.0/ui-bootstrap-tpls.js”> </script> <scriptsrc=“scripts/app.js”></script> <scriptsrc=“scripts/controllers/seat.js”></script> <scriptsrc=“scripts/services/seatservice.js”></script> <scriptsrc=“scripts/services/accountservice.js”></script> </body> </html> Youmayhavealsonoticedtwostrange-lookingattributesinthehtmltags:ng-appandngcontroller.TheseareAngularJSdirectivesthatpointtothewebpagebeingan AngularJSapplication,andthatthecontainerdivwilluseaSeatCtrlcontroller. Now,wewillneedthefollowingfilesplacedinourscriptsdirectory.Thefirstoneisthe initializationfileapp.js: ‘usestrict’; angular.module(‘ticketApp’,[‘ngResource’,‘ngRoute’,‘ui.bootstrap’]) .config(function($routeProvider){ $routeProvider.when(‘/’,{ controller:‘SeatCtrl’ }).otherwise({ redirectTo:‘/’ }); }); Nextwewillinitializetheaddressofourseatresourcein scripts/services/seatservice.js: ‘usestrict’; angular.module(‘ticketApp’).service(‘SeatService’, functionSeatService($resource){ return$resource(‘rest/seat/:seatId’,{ seatId:‘@id’ },{ query:{ method:‘GET’, isArray:true }, book:{ method:‘POST’ } }); }); Asyoucansee,wemappedourRESTURLtotheJavaScriptcodealongwithtwoHTTP methods:GETandPOST.Theywillbecalledbythecontrollertocommunicatewiththe server;thesamegoesforouraccountresource,asshowninthefollowingcode: ‘usestrict’; angular.module(‘ticketApp’).service(‘AccountService’, functionAccountService($resource){ return$resource(‘rest/account’,{},{ query:{ method:‘GET’, isArray:false }, reset:{ method:‘POST’ } }); }); Finally,wecreateasimplecontrollertoplaceourlogicat scripts/controllers/seat.js: ‘usestrict’; angular.module(‘ticketApp’).controller( ‘SeatCtrl’, function($scope,SeatService,AccountService){ $scope.seats=SeatService.query(); $scope.account=AccountService.query(); $scope.alerts=[]; $scope.bookTicket=function(seat){ seat.$book({},functionsuccess(){ $scope.account.$query(); },functionerr(httpResponse){ $scope.alerts.push({ type:‘danger’, msg:‘Errorbookingticketforseat‘ +httpResponse.config.data.id+‘:‘ +httpResponse.data.entity }); }); }; $scope.closeAlert=function(index){ $scope.alerts.splice(index,1); }; $scope.clearWarnings=function(){ $scope.alerts.length=0; }; $scope.resetAccount=function(){ $scope.account.$reset(); }; }); Thehighlightedportionsofcodearecallstotheserviceswedefinedpreviously.For instance,$scope.seats=SeatService.query()willissueaGETrequesttoretrievealist ofseatsintheJSONformat.Thecaseforseat.$bookissimilar;itwillissueaPOST requesttobookaspecificseat. OurwholeJavaScriptlogicisnowinplace.OnefinalmoveistoplacesomeHTMLcode boundtoitinourindex.htmlfile.Insertthefollowingcodeintheindex.htmlfile,inside thecontentdiv: <alertng-repeat=“alertinalerts”type=“alert.type” close=“closeAlert($index)”>{{alert.msg}} </alert> <divclass=“panelpanel-default”> <divclass=“panel-heading”> <h3class=“panel-title”>Ticketbooking</h3> </div> <divclass=“panel-body”> <p> Remainingmoney:<spanclass=“badge”>{{account.balance}} </span> </p> <br/> <buttontype=“button”class=“btnbtn-primarybtn-xs” ng-click=“clearWarnings()”>Clearwarnings </button> <buttontype=“button”class=“btnbtn-warningbtn-xs” ng-click=“resetAccount()”>Resetaccount </button> </div> <tableclass=“tabletable-hovertable-striped”> <thead><th>ID</th><th>Name</th><th>Price</th> <th>Booked</th><th>Book</th></thead> <tbody> <trng-repeat=“seatinseats”> <td>{{seat.id}}</td> <td>{{seat.name}}</td> <td>${{seat.price}}</td> <td><span class=“glyphiconglyphicon-{{seat.booked?‘ok’ :‘remove’}}”></span></td> <td> <buttontype=“button” class=“btnbtn-primary{{seat.booked? ‘disabled’:”}}btn-xs”ng-click=“bookTicket(seat)”>Book </button> </td> </tr> </tbody> </table> ThecodeissimilartotheJSFtableswecreatedintheearlierchapters.Whatisimportant tousisthatthe{{}}symbolsareusedbyAngularJStobindthedisplayeddatawitha variableinacontroller,which,infact,isarepresentationofourRESTendpoints. Additionally,theng-clickdirectivesareboundtotheappropriatemethodsinthe controller.ThebookTicketmethodissuesaseat.$bookcall,whichispropagatedasa POSTrequesttoourbackend. Wecannowdeployourapplicationtotheserver.Aftergoingto http://localhost:8080/ticket-agency-ws/index.htmlinyourbrowser,youshould seeyourapplicationrunning,asshowninthefollowingscreenshot: Youcanusethedeveloper’stoolsinChrome(orFireBuginMozillaFirefox)toinspectthe restcallsthataredoneagainsttheserver;simplypressF12andswitchtotheNetwork tab: Congratulations!YouhavejustcreatedamodernInternetapplicationandcombineditwith aRESTAPIthatwasearlierusedbyastandaloneconsoleapplication! ChoosingbetweenSOAPandRESTservices ThechoiceofadoptingSOAPratherthanRESTdependsonyourapplication’s requirements.SOAPwebservicesareexposedusingtheirownwell-definedprotocoland focusonexposingpiecesofapplicationlogicasservices.Soifyourrequirementisto consumebusinessservicesthatareexposedusingawell-definedandnegotiatedcontract (betweentheserviceconsumerandserviceprovider),SOAPwebservicesareaperfect match. Ontheotherhand,ifyouneedtoaccesssomeserverresourcesusingstatelessHTTP invocationsandaslittleaspossibleofthenavigationbarofyourbrowser,youshould probablygowithRESTfulwebservices. Thatbeingsaid,theremaystillbesomescenariosthatcouldfitboththeoptions,andyou arefreetochoosewhicheverwebservicesuitsyourrequirementsthebest.Recently, RESThasgainedpopularity,thankstoitsinteroperability.WeuseonlytheHTTPprotocol andJSON,whichalmosteverylanguagecanhandle.Therefore,aRESTAPIdeveloped usingJavaEEcanbeusedbyawidevarietyofclientsalongwithmobiledevices.Often, thisfeatureisadealbreakerwhenitcomestodesigningasystem. Summary Inthischapter,weintroducedsomeofthebasicwebservicesconceptssothatyoucould getacquaintedwiththesetechnologiesbeforeusingthemtoenhanceyourticket application. Then,wewentthroughSOAP-basedwebservicesthatarebasedonacontractbetweenthe serviceandclientdefinedbytheWSDLfile.SOAPwebservicesareanexcellentoptionto integratesystemswhenyouhavewell-defined,abstractoperationsexposedusingstandard XMLfiles. Then,wediscussedRESTservices.ThekeytotheRESTmethodologyistowriteweb servicesusinganinterfacethatisalreadywellknownandwidelyused:theURI.Thetwist hereistoidentifythekeysystemresources(thiscanbeentities,collections,oranything elsethedesignerthinksisworthyofhavingitsownURI)andexposethemusingstandard methodsthataremappedtostandardmethods.Inthiscase,theHTTPverbsaremappedto resource-specificsemantics. WecreatedtwoapplicationsthatuseourRESTAPI:oneconsole-basedandonewritten purelyinJavaScriptusingAngularJS.BothoftheseusethesameRESTendpointsandthe secondoneknowsonlyaboutJSON;ithasnoideaabouttheJavaclassesunderneath(or evenaboutJava). Wediscussedapplicationserverresourcesalot.Inthenextchapter,wewillexplore anotherapproachforclient-servercommunication:WebSockets. Chapter8.AddingWebSockets WebSocketsareoneofthebiggestadditionsinJavaEE7.Inthischapter,wewillexplore thenewpossibilitiesthattheyprovidetoadeveloper.Inourticketbookingapplications, wealreadyusedawidevarietyofapproachestoinformtheclientsabouteventsoccurring ontheserverside.Theseincludethefollowing: JSFpolling JavaMessagingService(JMS)messages RESTrequests RemoteEJBrequests Allofthem,besidesJMS,werebasedontheassumptionthattheclientwillberesponsible foraskingtheserveraboutthestateoftheapplication.Insomecases,suchaschecking whethersomeoneelsehasnotbookedaticketduringourinteractionwiththeapplication, thisisawastefulstrategy;theserverisinthepositiontoinformclientswhenitisneeded. What’smore,itfeelslikethedevelopermusthacktheHTTPprotocoltogetanotification fromaservertotheclient.Thisisarequirementthathastobeimplementedinmostweb applications,andtherefore,deservesastandardizedsolutionthatcanbeappliedbythe developersinmultipleprojectswithoutmucheffort. WebSocketsarechangingthegamefordevelopers.Theyreplacetherequest-response paradigminwhichtheclientalwaysinitiatesthecommunicationwithatwo-point bidirectionalmessagingsystem.Aftertheinitialconnection,bothsidescansend independentmessagestoeachotheraslongasthesessionisalive.Thismeansthatwecan easilycreatewebapplicationsthatwillautomaticallyrefreshtheirstatewithup-to-date datafromtheserver.YouprobablyhavealreadyseenthiskindofbehaviorinGoogleDocs orlivebroadcastsonnewssites.Nowwecanachievethesameeffectinasimplerand moreefficientwaythaninearlierversionsofJavaEnterpriseEdition.Inthischapter,we willtrytoleveragethesenew,excitingfeaturesthatcomewithWebSocketsinJavaEE7 thankstoJSR356(https://jcp.org/en/jsr/detail?id=356)andHTML5. Inthischapter,youwilllearnthefollowingtopics: HowWebSocketswork HowtocreateaWebSocketendpointinJavaEE7 HowtocreateanHTML5/AngularJSclientthatwillacceptpushnotificationsfrom anapplicationdeployedonWildFly AnoverviewofWebSockets AWebSocketsessionbetweentheclientandserverisbuiltuponastandardTCP connection.AlthoughtheWebSocketprotocolhasitsowncontrolframes(mainlytocreate andsustaintheconnection)codedbytheInternetEngineeringTaskForceintheRFC6455 (http://tools.ietf.org/html/rfc6455),thepeersarenotobligedtouseanyspecificformatto exchangeapplicationdata.Youmayuseplaintext,XML,JSON,oranythingelseto transmityourdata.Asyouprobablyremember,thisisquitedifferentfromSOAP-based WebServices,whichhadbloatedspecificationsoftheexchangeprotocol.Thesamegoes forRESTfularchitectures;wenolongerhavethepredefinedverbmethodsfromHTTP (GET,PUT,POST,andDELETE),statuscodes,andthewholesemanticsofanHTTP request. ThislibertymeansthatWebSocketsareprettylowlevelcomparedtothetechnologiesthat wehaveuseduptothispoint,butthankstothis,thecommunicationoverheadisminimal. TheprotocolislessverbosethanSOAPorRESTfulHTTP,whichallowsustoachieve higherperformance.This,however,comeswithaprice.Weusuallyliketousethefeatures ofhigher-levelprotocols(suchashorizontalscalingandrichURLsemantics),andwith WebSockets,wewouldneedtowritethembyhand.ForstandardCRUD-likeoperations,it wouldbeeasiertouseaRESTendpointthancreateeverythingfromscratch. WhatdowegetfromWebSocketscomparedtothestandardHTTPcommunication?First ofall,adirectconnectionbetweentwopeers.Normally,whenyouconnecttoawebserver (whichcan,forinstance,handleaRESTendpoint),everysubsequentcallisanewTCP connection,andyourmachineistreatedlikeitisadifferentoneeverytimeyoumakea request.Youcan,ofcourse,simulateastatefulbehavior(sothattheserverwillrecognize yourmachinebetweendifferentrequests)usingcookiesandincreasetheperformanceby reusingthesameconnectioninashortperiodoftimeforaspecificclient,butbasically,it isaworkaroundtoovercomethelimitationsoftheHTTPprotocol. OnceyouestablishaWebSocketconnectionbetweenaserverandclient,youcanusethe samesession(andunderlyingTCPconnection)duringthewholecommunication.Both sidesareawareofitandcansenddataindependentlyinafull-duplexmanner(bothsides cansendandreceivedatasimultaneously).UsingplainHTTP,thereisnowayforthe servertospontaneouslystartsendingdatatotheclientwithoutanyrequestfromitsside. What’smore,theserverisawareofallofitsconnectedWebSocketclients,andcaneven senddatabetweenthem! Thecurrentsolutionthatincludestryingtosimulatereal-timedatadeliveryusingHTTP protocolcanputalotofstressonthewebserver.Polling(askingtheserverabout updates),longpolling(delayingthecompletionofarequesttothemomentwhenan updateisready),andstreaming(aComet-basedsolutionwithaconstantlyopenHTTP response)areallwaystohacktheprotocoltodothingsthatitwasn’tdesignedforand havetheirownlimitations.Thankstotheeliminationofunnecessarychecks,WebSockets canheavilyreducethenumberofHTTPrequeststhathavetobehandledbytheweb server.Theupdatesaredeliveredtotheuserwithasmallerlatencybecauseweonlyneed oneround-tripthroughthenetworktogetthedesiredinformation(itispushedbythe serverimmediately). AllofthesefeaturesmakeWebSocketsagreatadditiontotheJavaEEplatform,which fillsthegapsneededtoeasilyfinishspecifictasks,suchassendingupdates,notifications, andorchestratingmultipleclientinteractions.Despitetheseadvantages,WebSocketsare notintendedtoreplaceRESTorSOAPWebServices.Theydonotscalesowell horizontally(theyarehardtodistributebecauseoftheirstatefulnature),andtheylack mostofthefeaturesthatareutilizedinwebapplications.URLsemantics,complex security,compression,andmanyotherfeaturesarestillbetterrealizedusingother technologies. HowdoWebSocketswork ToinitiateaWebSocketsession,theclientmustsendanHTTPrequestwithanUpgrade: websocketheaderfield.Thisinformstheserverthatthepeerclienthasaskedtheserverto switchtotheWebSocketprotocol. Note YoumaynoticethatthesamehappensinWildFlyforRemoteEJBs;theinitialconnection ismadeusinganHTTPrequest,andislaterswitchedtotheremoteprotocolthankstothe Upgrademechanism.ThestandardUpgradeheaderfieldcanbeusedtohandleany protocol,otherthanHTTP,whichisacceptedbybothsides(theclientandserver).In WildFly,thisallowsyoutoreusetheHTTPport(80/8080)forotherprotocolsand thereforeminimisethenumberofrequiredportsthatshouldbeconfigured. Iftheservercan“understand”theWebSocketprotocol,theclientandserverthenproceed withthehandshakingphase.Theynegotiatetheversionoftheprotocol,exchangesecurity keys,andifeverythinggoeswell,thepeerscangotothedatatransferphase.Fromnow on,thecommunicationisonlydoneusingtheWebSocketprotocol.Itisnotpossibleto exchangeanyHTTPframesusingthecurrentconnection.Thewholelifecycleofa connectioncanbesummarizedinthefollowingdiagram: AsampleHTTPrequestfromaJavaScriptapplicationtoaWildFlyserverwouldlook similartothis: GET/ticket-agency-websockets/ticketsHTTP/1.1 Upgrade:websocket Connection:Upgrade Host:localhost:8080 Origin:http://localhost:8080Pragma:no-cache Cache-Control:no-cache Sec-WebSocket-Key:TrjgyVjzLK4Lt5s8GzlFhA== Sec-WebSocket-Version:13 Sec-WebSocket-Extensions:permessage-deflate;client_max_window_bits,xwebkit-deflate-frame User-Agent:Mozilla/5.0(WindowsNT6.3;WOW64)AppleWebKit/537.36(KHTML, likeGecko)Chrome/34.0.1847.116Safari/537.36 Cookie:[45byteswerestripped] WecanseethattheclientrequestsanupgradeconnectionwithWebSocketasthetarget protocolontheURL/ticket-agency-websockets/tickets.Itadditionallypasses informationabouttherequestedversionandkey. Iftheserversupportstherequestprotocolandalltherequireddataispassedbytheclient, thenitwouldrespondwiththefollowingframe: HTTP/1.1101SwitchingProtocols X-Powered-By:Undertow1 Server:Wildfly8 Origin:http://localhost:8080 Upgrade:WebSocket Sec-WebSocket-Accept:ZEAab1TcSQCmv8RsLHg4RL/TpHw= Date:Sun,13Apr201417:04:00GMT Connection:Upgrade Sec-WebSocket-Location:ws://localhost:8080/ticket-agencywebsockets/tickets Content-Length:0 Thestatuscodeoftheresponseis101(switchingprotocols)andwecanseethattheserver isnowgoingtostartusingtheWebSocketprotocol.TheTCPconnectioninitiallyusedfor theHTTPrequestisnowthebaseoftheWebSocketsessionandcanbeusedfor transmissions.IftheclienttriestoaccessaURL,whichisonlyhandledbyanother protocol,thentheservercanasktheclienttodoanupgraderequest.Theserverusesthe 426(upgraderequired)statuscodeinsuchcases. Note Theinitialconnectioncreationhassomeoverhead(becauseoftheHTTPframesthatare exchangedbetweenthepeers),butafteritiscompleted,newmessageshaveonly2bytes ofadditionalheaders.Thismeansthatwhenwehavealargenumberofsmallmessages, WebSocketwillbeanorderofmagnitudefasterthanRESTprotocolssimplybecausethere islessdatatotransmit! IfyouarewonderingaboutthebrowsersupportofWebSockets,youcanlookitupat http://caniuse.com/websockets.Allnewversionsofmajorbrowserscurrentlysupport WebSockets;thetotalcoverageisestimated(atthetimeofwriting)at74percent.Youcan seethisinthefollowingscreenshot: Afterthistheoreticalintroduction,wearereadytojumpintoaction.Wecannowcreate ourfirstWebSocketendpoint! Creatingourfirstendpoint Let’sstartwithasimpleexample: packagecom.packtpub.wflydevelopment.chapter8.boundary; importjavax.websocket.EndpointConfig; importjavax.websocket.OnOpen; importjavax.websocket.Session; importjavax.websocket.server.ServerEndpoint; importjava.io.IOException; @ServerEndpoint(“/hello”) publicclassHelloEndpoint{ @OnOpen publicvoidopen(Sessionsession,EndpointConfigconf)throws IOException{ session.getBasicRemote().sendText(“Hi!”); } } JavaEE7specificationhastakenintoaccountdeveloperfriendliness,whichcanbe clearlyseeninthegivenexample.InordertodefineyourWebSocketendpoint,youjust needafewannotationsonaPlainOldJavaObject(POJO).Thefirstannotation @ServerEndpoint(“/hello”)definesapathtoyourendpoint.It’sagoodtimetodiscuss theendpoint’sfulladdress.Weplacedthissampleintheapplicationnamedticketagency-websockets.Duringthedeploymentofapplication,youcanspotinformationin theWildFlylogaboutendpointscreation,asshowninthefollowingcommandline: 02:21:35,182INFO[io.undertow.websockets.jsr](MSCservicethread1-7) UT026003:Addingannotatedserverendpointclass com.packtpub.wflydevelopment.chapter8.boundary.FirstEndpointforpath /hello 02:21:35,401INFO[org.jboss.resteasy.spi.ResteasyDeployment](MSCservice thread1-7)Deployingjavax.ws.rs.core.Application:class com.packtpub.wflydevelopment.chapter8.webservice.JaxRsActivator$Proxy$_$$_WeldCli 02:21:35,437INFO[org.wildfly.extension.undertow](MSCservicethread17)JBAS017534:Registeredwebcontext:/ticket-agency-websockets ThefullURLoftheendpointisws://localhost:8080/ticket-agencywebsockets/hello,whichisjustaconcatenationoftheserverandapplicationaddress withanendpointpathonanappropriateprotocol. Thesecondusedannotation@OnOpendefinestheendpointbehaviorwhentheconnection fromtheclientisopened.It’snottheonlybehavior-relatedannotationoftheWebSocket endpoint.Let’slooktothefollowingtable: Annotation Description @OnOpen Theconnectionisopen.Withthisannotation,wecanusetheSessionandEndpointConfigparameters.Thefirstparameterrepresentstheconnectiontotheuserandallowsfurthercommunication.The secondoneprovidessomeclient-relatedinformation. @OnMessage Thisannotationisexecutedwhenamessagefromtheclientisbeingreceived.Insuchamethod,youcanjusthaveSessionandforexample,theStringparameter,wheretheStringparameter representsthereceivedmessage. @OnError Therearebadtimeswhenanerroroccurs.Withthisannotation,youcanretrieveaThrowableobjectapartfromstandardSession. @OnClose Whentheconnectionisclosed,itispossibletogetsomedataconcerningthiseventintheformoftheCloseReasontypeobject. ThereisonemoreinterestinglineinourHelloEndpoint.UsingtheSessionobject,itis possibletocommunicatewiththeclient.ThisclearlyshowsthatinWebSockets,twodirectionalcommunicationiseasilypossible.Inthisexample,wedecidedtorespondtoa connectedusersynchronously(getBasicRemote())withjustatextmessageHi! (sendText(String)).Ofcourse,it’salsopossibletocommunicateasynchronouslyand send,forexample,sendingbinarymessagesusingyourownbinarybandwidthsaving protocol.Wewillpresentsomeoftheseprocessesinthenextexample. Expandingourclientapplication It’stimetoshowhowyoucanleveragetheWebSocketfeaturesinreallife.Intheprevious chapter,Chapter7,AddingWebServicestoYourApplications,wecreatedtheticket bookingapplicationbasedontheRESTAPIandAngularJSframework.Itwasclearly missingoneimportantfeature:theapplicationdidnotshowinformationconcerningticket purchasesofotherusers.ThisisaperfectusecaseforWebSockets! Sincewe’rejustaddingafeaturetoourpreviousapp,wewillonlydescribethechanges wewillintroducetoit. Inthisexample,wewouldliketobeabletoinformallcurrentusersaboutotherpurchases. Thismeansthatwehavetostoreinformationaboutactivesessions.Let’sstartwiththe registrytypeobject,whichwillservethispurpose.WecanuseaSingletonsessionbean forthistask,asshowninthefollowingcode: @Singleton publicclassSessionRegistry{ privatefinalSet<Session>sessions=newHashSet<>(); @Lock(LockType.READ) publicSet<Session>getAll(){ returnCollections.unmodifiableSet(sessions); } @Lock(LockType.WRITE) publicvoidadd(Sessionsession){ sessions.add(session); } @Lock(LockType.WRITE) publicvoidremove(Sessionsession){ sessions.remove(session); } } WecoulduseCollections.synchronizedSetfromstandardJavalibrariesbutit’sagreat chancetorememberwhatwedescribedinChapter3,IntroducingJavaEE7–EJBs,about container-basedconcurrency.InSessionRegistry,wedefinedsomebasicmethodsto add,get,andremovesessions.Forthesakeofcollectionthreadsafetyduringretrieval,we returnanunmodifiableview. Wedefinedtheregistry,sonowwecanmovetotheendpointdefinition.Wewillneeda POJO,whichwilluseournewlydefinedregistryasshown: @ServerEndpoint(“/tickets”) publicclassTicketEndpoint{ @Inject privateSessionRegistrysessionRegistry; @OnOpen publicvoidopen(Sessionsession,EndpointConfigconf){ sessionRegistry.add(session); } @OnClose publicvoidclose(Sessionsession,CloseReasonreason){ sessionRegistry.remove(session); } publicvoidsend(@ObservesSeatseat){ sessionRegistry.getAll().forEach(session-> session.getAsyncRemote().sendText(toJson(seat))); } privateStringtoJson(Seatseat){ finalJsonObjectjsonObject=Json.createObjectBuilder() .add(“id”,seat.getId()) .add(“booked”,seat.isBooked()) .build(); returnjsonObject.toString(); } } Ourendpointisdefinedinthe/ticketsaddress.WeinjectedaSessionRepositorytoour endpoint.During@OnOpen,weaddSessionstotheregistry,andduring@OnClose,wejust removethem.MessagesendingisperformedontheCDIevent(the@Observers annotation),whichisalreadyfiredinourcodeduringTheatreBox.buyTicket(int).In oursendmethod,weretrieveallsessionsfromSessionRepository,andforeachofthem, weasynchronouslysendinformationaboutbookedseats.Wedon’treallyneed informationaboutalltheSeatfieldstorealizethisfeature.That’sthereasonwhywedon’t usetheautomaticJSONserializationweknowfromthelastchapterhere.Instead,we decidedtouseaminimalisticJSONobject,whichprovidesonlytherequireddata.Todo this,weusedthenewJavaAPIforJSONProcessing(JSR-353).Usingafluent-likeAPI, we’reabletocreateaJSONobjectandaddtwofieldstoit.Then,wejustconvertJSONto thestring,whichissentinatextmessage. BecauseinourexamplewesendmessagesinresponsetoaCDIevent,wedon’thave(in theeventhandler)anout-of-the-boxreferencetoanyofthesessions.Wehavetouseour sessionRegistryobjecttoaccesstheactiveones.However,ifwewouldliketodothe samethingbut,forexample,inthe@OnMessagemethod,thenitispossibletogetallactive sessionsjustbyexecutingthesession.getOpenSessions()method. Theseareallthechangesrequiredtoperformonthebackendside.Now,wehaveto modifyourAngularJSfrontendtoleveragetheaddedfeature.Thegoodnewsisthat JavaScriptalreadyincludesclassesthatcanbeusedtoperformWebSocket communication!Thereareafewlinesofcodewehavetoaddinsidethemoduledefinedin theseat.jsfile,whichareasfollows: varws=newWebSocket(“ws://localhost:8080/ticket-agencywebsockets/tickets”); ws.onmessage=function(message){ varreceivedData=message.data; varbookedSeat=JSON.parse(receivedData); $scope.$apply(function(){ for(vari=0;i<$scope.seats.length;i++){ if($scope.seats[i].id===bookedSeat.id){ $scope.seats[i].booked=bookedSeat.booked; break; } } }); }; Thecodeisverysimple.WejustcreatetheWebSocketobjectusingtheURLtoour endpoint,andthenwedefinetheonmessagefunctioninthatobject.Duringthefunction execution,thereceivedmessageisautomaticallyparsedfromtheJSONtoJavaScript object.Then,in$scope.$apply,wejustiteratethroughourseats,andiftheIDmatches, weupdatethebookedstate.Wehavetouse$scope.$applybecausewearetouchingan AngularobjectfromoutsidetheAngularworld(theonmessagefunction).Modifications performedon$scope.seatsareautomaticallyvisibleonthewebsite.Withthis,wecan justopenourticketbookingwebsiteintwobrowsersessions,andseethatwhenoneuser buysaticket,thesecondusersseesalmostinstantlythattheseatstateischangedto booked. WecanenhanceourapplicationalittletoinformusersiftheWebSocketconnectionis reallyworking.Let’sjustdefineonopenandonclosefunctionsforthispurpose: ws.onopen=function(event){ $scope.$apply(function(){ $scope.alerts.push({ type:‘info’, msg:‘Pushconnectionfromserverisworking’ }); }); }; ws.onclose=function(event){ $scope.$apply(function(){ $scope.alerts.push({ type:‘warning’, msg:‘Erroronpushconnectionfromserver‘ }); }); }; Toinformusersaboutaconnection’sstate,wepushdifferenttypesofalerts.Ofcourse, againwe’retouchingtheAngularworldfromtheoutside,sowehavetoperformall operationsonAngularfromthe$scope.$applyfunction. Runningthedescribedcoderesultsinthenotification,whichisvisibleinthefollowing screenshot: However,iftheserverfailsafteropeningthewebsite,youmightgetanerrorasshownin thefollowingscreenshot: TransformingPOJOstoJSON Inourcurrentexample,wetransformedourSeatobjecttoJSONmanually.Normally,we don’twanttodoitthisway;therearemanylibrariesthatwilldothetransformationforus. OneofthemisGSONfromGoogle.Additionally,wecanregisteranencoder/decoder classforaWebSocketendpointthatwilldothetransformationautomatically.Let’slookat howwecanrefactorourcurrentsolutiontouseanencoder. Firstofall,wemustaddGSONtoourclasspath.TherequiredMavendependencyisas follows: <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.3</version> </dependency> Next,weneedtoprovideanimplementationofthejavax.websocket.Encoder.Text interface.Therearealsoversionsofthejavax.websocket.Encoder.Textinterfacefor binaryandstreameddata(forbothbinaryandtextformats).Acorrespondinghierarchyof interfacesisalsoavailablefordecoders(javax.websocket.Decoder).Ourimplementation israthersimple.Thisisshowninthefollowingcodesnippet: publicclassJSONEncoderimplementsEncoder.Text<Object>{ privateGsongson; @Override publicvoidinit(EndpointConfigconfig){ gson=newGson();[1] } @Override publicvoiddestroy(){ //donothing } @Override publicStringencode(Objectobject)throwsEncodeException{ returngson.toJson(object);[2] } } First,wecreateaninstanceofGSONintheinitmethod;thisactionwillbeexecuted whentheendpointiscreated.Next,intheencodemethod,whichiscalledeverytime,we sendanobjectthroughanendpoint.WeuseJSONcommandtocreateJSONfroman object.Thisisquiteconcisewhenwethinkhowreusablethislittleclassis.Ifyouwant morecontrolontheJSONgenerationprocess,youcanusetheGsonBuilderclassto configuretheGsonobjectbeforecreation.Wehavetheencoderinplace.Nowit’stimeto alterourendpoint: @ServerEndpoint(value=“/tickets”,encoders={JSONEncoder.class})[1] publicclassTicketEndpoint{ @Inject privateSessionRegistrysessionRegistry; @OnOpen publicvoidopen(Sessionsession,EndpointConfigconf){ sessionRegistry.add(session); } @OnClose publicvoidclose(Sessionsession,CloseReasonreason){ sessionRegistry.remove(session); } publicvoidsend(@ObservesSeatseat){ sessionRegistry.getAll().forEach(session-> session.getAsyncRemote().sendObject(seat));[2] } } Thefirstchangeisdoneonthe@ServerEndpointannotation.Wehavetodefinealistof supportedencoders;wesimplypassourJSONEncoder.classwrappedinanarray. Additionally,wehavetopasstheendpointnameusingthevalueattribute. Earlier,weusedthesendTextmethodtopassastringcontainingamanuallycreated JSON.Now,wewanttosendanobjectandlettheencoderhandletheJSONgeneration; therefore,we’llusethegetAsyncRemote().sendObject()method.Andthat’sall.Our endpointisreadytobeused.Itwillworkthesameastheearlierversion,butnowour objectswillbefullyserializedtoJSON,sotheywillcontaineveryfield,notonlyidand booked. Afterdeployingtheserver,youcanconnecttotheWebSocketendpointusingoneofthe Chromeextensions,forinstance,theDarkWebSocketterminalfromtheChromestore (usethews://localhost:8080/ticket-agency-websockets/ticketsaddress).When youbookticketsusingthewebapplication,theWebSocketterminalshouldshow somethingsimilartotheoutputshowninthefollowingscreenshot: Ofcourse,itispossibletousedifferentformatsotherthanJSON.Ifyouwanttoachieve betterperformance(whenitcomestotheserializationtimeandpayloadsize),youmay wanttotryoutbinaryserializerssuchasKryo(https://github.com/EsotericSoftware/kryo). TheymaynotbesupportedbyJavaScript,butmaycomeinhandyifyouwouldliketouse WebSocketsforotherclientstoo.Tyrus(https://tyrus.java.net/)isareference implementationoftheWebSocketstandardforJava;youcanuseitinyourstandalone desktopapplications.Inthatcase,besidestheencoder(whichisusedtosendmessages), youwouldalsoneedtocreateadecoder,whichcanautomaticallytransformincoming messages. AnalternativetoWebSockets Theexamplewepresentedinthischapterispossibletobeimplementedusinganolder, lesser-knowntechnologynamedServer-SentEvents(SSE).SSEallowsforone-way communicationfromtheservertoclientoverHTTP.ItismuchsimplerthanWebSockets buthasabuilt-insupportforthingssuchasautomaticreconnectionandeventidentifiers. WebSocketsaredefinitelymorepowerful,butarenottheonlywaytopassevents,so whenyouneedtoimplementsomenotificationsfromtheserverside,rememberabout SSE. AnotheroptionistoexplorethemechanismsorientedaroundtheComettechniques. Multipleimplementationsareavailableandmostofthemusedifferentmethodsof transportationtoachievetheirgoals.Acomprehensivecomparisonisavailableat http://cometdaily.com/maturity.html. Summary Inthischapter,wemanagedtointroducethenewlow-leveltypeofcommunication.We presentedhowitworksunderneathandcomparestoSOAPandRESTintroducedinthe previouschapter.Wealsodiscussedhowthenewapproachchangesthedevelopmentof webapplications. Ourticketbookingapplicationwasfurtherenhancedtoshowusersthechangingstateof theseatsusingpush-likenotifications.Thenewadditionsrequiredverylittlecodechanges inourexistingprojectwhenwetakeintoaccounthowmuchweareabletoachievewith them.ThefluentintegrationofWebSocketsfromJavaEE7withtheAngularJS applicationisanothergreatshowcaseofflexibility,whichcomeswiththenewversionof theJavaEEplatform. Inthenextchapter,youwilllearnmoreaboutWildFlyadministrationandmanagement,so thatwecanexploremoresystem-widefeaturesofJavaEE7inthefollowingchapters. Chapter9.ManagingtheApplicationServer Sofar,wehavecoveredmanyJavaEnterpriseexamplesanddeployedthemonthe applicationserver.Wewillnowdiveheadlongintothevastandvariedoceanof instrumentsthatareavailabletomanagetheapplicationserver.Thepurposeofthis chapteristoteachyouhowtousetheseinstrumentstoadministerandmonitorallthe resourcesavailableontheapplicationserver. Hereisthelistoftopicswewillcoverinthischapter: AnintroductiontotheWildFlyCommand-lineInterface(CLI) HowtocreatescriptswiththeCLI Howtoprogrammaticallymanageyourserverresourcesusingscriptinglanguages andWildFly’sclientAPI Howtoenforcerole-basedsecurityforadministrators EnteringtheWildFlyCLI ACLIisacompletemanagementtoolthatcanbeusedtostartandstopservers,deploy andundeployapplications,configuresystemresources,andperformotheradministrative tasks.Operationsinitcanbeexecutedinanatomicwayorinbatchmodes,allowingyou torunmultipletasksasagroup. LaunchingtheCLI IfyouareusingWindows,youcanstarttheCLIbyenteringthefollowingcommandfrom theJBOSS_HOME/binfolderusingtheCommandPrompt: jboss-cli.bat Alternatively,enterthefollowingcommandifyouareusingLinux: ./jboss-cli.sh OncetheCLIhasstarted,youcanconnecttothemanagedserverinstanceusingthe connectcommand,whichbydefaultconnectstolocalhostandthe9990port: [disconnected/]connect [standalone@localhost:9990/] Ifyouwanttoconnecttoanotheraddressorport,youcansimplypassittotheconnect command,asfollows: [disconnected/]connect192.168.1.1 [[email protected]:9990/] ItisalsopossibletolaunchaCLIintheconnectedmode;thisallowsittobeconnected automaticallyandtopossiblyspecifythecommandstobeexecuted.Forexample,the followingshellcommandautomaticallyconnectstoaWildFlyinstanceandissuesa shutdowncommand: >jboss-cli.bat—connectcommand=:shutdown {“outcome”=>“success”} CLIisespeciallyusefulfortheautomationofyoursoftwaredevelopmentprocess —ContinuousIntegration(CI)andproductionenvironmentmanagementsystemscan automaticallycontrolthelifecycleofyourapplicationserverwithtoolssuchasChef (https://www.getchef.com/)orPuppet(http://puppetlabs.com/).Itmightbehandyifyou wouldliketominimizethenumberofmanualtasksthatarerequiredtobedonetodeploy anapplication. Connectingfromremotehosts Startingfromthe7.1.0Betareleaseoftheapplicationserver,securityisenabledonAS managementinterfacesbydefaulttopreventunauthorizedremoteaccesstotheapplication server.Althoughlocalclientsoftheapplicationserverarestillallowedtoaccess managementinterfaceswithoutanyauthentication,remoteclientsneedtoentera username/passwordpairtoaccessaCLI.Here’sanexamplesessionthatsuccessfully connectstoaremotehostwiththeIPaddress10.13.2.255: [disconnected/]connect10.13.2.255 Authenticatingagainstsecurityrealm:ManagementRealm Username:administrator Password: [[email protected]:9990/] PleaserefertoChapter2,YourFirstJavaEEApplicationonWildFly,formore informationaboutcreatingauserwiththeadd-user.shshellcommand. UsingaCLIinthegraphicalmode Aninterestingoptionavailableforthecommand-lineinterfaceisthegraphicalmode, whichcanbeactivatedbyaddingthe—guiparametertotheshellscript: jboss-cli.bat—gui Here’showCLIlooksinthegraphicalmode: Asdescribedinthelabel,theresourcewillexpandwhenyouclickonafolder;onthe otherhand,ifyouright-clickonanode,youcanfireanoperationonit.Thegraphical modecouldbeusefultoexplorethepossibleconfigurationvaluesorifyouarenotabig fanofconsoletools. ThenextsectiondiscusseshowtoconstructCLIcommands,whichcanbeexecutedeither intheterminalmodeorthegraphicalmode. ConstructingCLIcommands AllCLIoperationrequestsallowyoutohavelow-levelinteractionswiththeserver managementmodel.Theyprovideacontrolledwaytoedittheserverconfigurations.An operationrequestconsistsofthreeparts: Anaddressthatisprefixedwith/ Anoperationnamethatisprefixedwith: Anoptionalsetofparameterscontainedwithin() Determiningtheresourceaddress Theserverconfigurationispresentedasahierarchicaltreeofaddressableresources.Each resourcenodeoffersadifferentsetofoperations.Theaddressspecifiestheresourcenode onwhichtoperformtheoperation.Anaddressusesthefollowingsyntax: /node-type=node-name Thenotationsareexplainedasfollows: node-type:Thisistheresourcenodetype.Thismapstoanelementnameinthe serverconfiguration. node-name:Thisspecifiestheresourcenodename.Thismapstothenameattributeof theelementintheserverconfiguration. Separateeachleveloftheresourcetreewithaslash(/).So,forexample,thefollowing CLIexpressionidentifiestheExampleDSdatasourceregisteredinthedatasource subsystem: /subsystem=datasources/data-source=ExampleDS Performingoperationsonresources Onceyouhaveidentifiedaresource,youcanperformoperationsontheresource.An operationusesthefollowingsyntax: :operation-name Sointhepreviousexample,youcanquerythelistofavailableresourcesforyournodesby addingtheread-resourcecommandattheendofit: /subsystem=datasources/:read-resource { “outcome”=>“success”, “result”=>{ “data-source”=>{“ExampleDS”=>undefined}, “jdbc-driver”=>{“h2”=>undefined}, “xa-data-source”=>undefined } } Ifyouwanttoqueryforaspecificattributeofyournode,youcanusetheread-attribute operationinstead.Forexample,thefollowingcodeshowshowtoreadtheenabled attributefromthedatasource: /subsystem=datasources/data-source=ExampleDS/:read-attribute(name=enabled) { “outcome”=>“success”, “result”=>false } Note Apartfromtheoperationsonaspecificresource,youcanalsoperformasetofcommands thatareavailableoneverypathofyourWildFlysubsystem,suchascdorlscommands. ThesecommandsareprettymuchequivalenttotheirUnixshellcounterparts,andthey allowyoutonavigatethroughtheWildFlysubsystems.Otherimportantadditionsarethe deployandundeploycommandsthat,asyoumightguess,allowyoutomanagethe deploymentofapplications.ThesekeycommandsarediscussedintheDeploying applicationsusingtheCLIsectionofthischapter. TheCLI,however,isnotjustaboutqueryingattributesfromtheWildFlysubsystems;you canalsosetattributesorcreateresources.Forexample,ifyouweretosettheHTTPport oftheHTTPconnector,youwillhavetousethecorrespondingwriteattributeonHTTP’s socketbindinginterface,shownasfollows: /socket-binding-group=standard-sockets/socket-binding=http/:writeattribute(name=port,value=8080) { “outcome”=>“success”,“response-headers”=>{ “operation-requires-reload”=>true, “process-state”=>“reload-required” } } Apartfromtheoperationsthatwehaveseensofar,whichcanbeperformedonevery resourceofyoursubsystems,therecanbespecialoperationsthatcanbeperformed exclusivelyononeresource.Forexample,withinthenamingsubsystem,youwillbeable toissueajndi-viewoperationthatwilldisplaythelistofJNDIbindings,asshowninthe followingcodesnippet: /subsystem=naming/:jndi-view { “outcome”=>“success”, “result”=>{“java:contexts”=>{ “java:”=>{ “TransactionManager”=>{ “class-name”=> “com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate”,“value”=> “com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate@afd978” }, … } Usingthetabcompletionhelper GettingtoknowalltheavailablecommandsintheCLIisaprettyhardtask;this managementinterfaceincludesanessentialfeature,thetabcompletion.Supposethe cursorispositionedatthebeginningofanemptyline;nowifyoutypein/andpressthe Tabkey,youwillgetthefollowinglistofalltheavailablenodetypes: [standalone@localhost:9990/]/ core-serviceextensionsocket-binding-group deploymentinterfacesubsystem deployment-overlaypathsystem-property Afterselectingthenodetype,youwanttoenterintothetreeofresources,sotype=and presstheTabkeyagain.Thiswillresultinalistofallthefollowingnodenamesavailable forthechosennodetype: [standalone@localhost:9990/]/subsystem= batchjdrresource-adapters datasourcesjmxsar deployment-scannerjpasecurity eejsfthreads ejb3loggingtransactions infinispanmailundertow ionamingwebservices jaxrspojoweld jcaremoting Afteryouhavefinishedwiththenodepath,addingacolon(:)attheendofthenodepath andpressingtheTabkeywilldisplayalltheavailableoperationnamesfortheselected node,whichisshownasfollows: [standalone@localhost:9990/]/subsystem=deploymentscanner/scanner=default: addread-resource read-attributeread-resource-description read-children-namesremove read-children-resourcesresolve-path read-children-typesundefine-attribute read-operation-descriptionwhoami read-operation-nameswrite-attribute Toseealltheparametersoftheaddoperation(aftertheoperationname),presstheTab key: [standalone@localhost:9990/]/subsystem=deploymentscanner/scanner=default:read-attribute( include-defaults=name= Choosetheparameteryouwantandspecifyitsvalueafter=: [standalone@localhost:9990/]/subsystem=deploymentscanner/scanner=default:read-attribute(name= runtime-failure-causes-rollbackscan-enabled relative-toscan-interval pathauto-deploy-zipped auto-deploy-explodeddeployment-timeout auto-deploy-xml Finally,whenalltheparametershavebeenspecified,add)andpressEntertoissuethe followingcommand: [standalone@localhost:9990/]/subsystem=deploymentscanner/scanner=default:read-attribute(name=scan-enabled) { “outcome”=>“success”, “result”=>true } DeployingapplicationsusingtheCLI Deployinganapplication(inthestandalonemode)canbeeasilyperformedbycopyingthe application’sarchivesintothedeploymentfolderofyourserverdistribution.That’sa prettyhandyoption;however,wewouldliketostresstheadvantageofusingaCLI,which offersawidechoiceofadditionaloptionswhendeployingandalsoprovidesthe opportunitytodeployapplicationsremotely. Allittakestodeployanapplication’sarchiveisaconnectiontothemanagementinstance, eitherlocalorremote,andbyissuingofthedeployshellcommand.Whenusedwithout arguments,thedeploycommandprovidesalistofapplicationsthatarecurrently deployed,asshowninthefollowingcommand: [disconnected/]connect [standalone@localhost:9990/]deployExampleApp.war IfyoufeedaresourcearchivesuchasaWARfiletotheshell,itwilldeployitonthe standaloneserverrightaway,asshowninthefollowingcommand: [standalone@localhost:9990/]deploy../MyApp.war Bydefault,aCLIusestheJBOSS_HOME/binfileasasourceforyourdeploymentarchives. Youcan,however,useabsolutepathswhenspecifyingthelocationofyourarchives;the CLIexpansionfacility(usingtheTabkey)makesthisoptionfairlysimple: [standalone@localhost:9990/]deployc:\deployments\MyApp.war Redeployingtheapplicationrequiresanadditionalflagtobeaddedtothedeploy command.Usethe-fargumenttoforcetheapplication’sredeployment: [standalone@localhost:9990/]deploy-f../MyApp.war Undeployingtheapplicationcanbedonethroughtheundeploycommand,whichtakesthe applicationthatisdeployedasanargument.Thisisshowninthefollowingcommand: [standalone@localhost:9990/]undeployMyApp.war BycheckingtheWildFlyconfigurationfile(forexample,standalone.xmlor domain.xml),youwillnoticethatthedeploymentelementforyourapplicationhasbeen removed. DeployingapplicationstoaWildFlydomain Whenyouaredeployinganapplicationusingthedomainmode,youwillhavetospecify towhichservergroupthedeploymentisassociatedwith.TheCLIletsyouchoose betweenthefollowingtwooptions: Deploytoallservergroups Deploytoasingleservergroup Wewilldiscussthesechoicesintwoseparatesections. Deployingtoallservergroups Ifthisoptionischosen,theapplicationwillbedeployedtoalltheavailableservergroups. The—all-server-groupsflagcanbeusedforthispurpose.Forexample,refertothe followingcode: [domain@localhost:9990/]deploy../application.ear—all-server-groups If,ontheotherhand,youwanttoundeployanapplicationfromalltheservergroupsthat belongtoadomain,youwillhavetoissuetheundeploycommandasshowninthe followingcommand: [domain@localhost:9990/]undeployapplication.ear—all-relevant-servergroups Note Youmighthavenoticedthattheundeploycommandusesthe—all-relevant-servergroupinsteadofthe—all-server-group.Thereasonforthisdifferenceisthatthe deploymentmightnotbeenabledonalltheservergroups;therefore,byusingthisoption, youwillactuallyundeployitfromalltheservergroupsinwhichthedeploymentis enabled. Deployingtoasingleservergroup Theotheroptionletsyouperformaselectivedeploymentofyourapplicationonlyonthe servergroupsyouindicate: [domain@localhost:9990/]deployapplication.ear—server-groups=mainserver-group Youarenotlimitedtoasingleservergroup,andyoucanseparatemultipleservergroups withacomma(,).Forexample,refertothefollowingcode: [domain@localhost:9990/]deployapplication.ear—server-groups=mainserver-group,other-server-group Successfullydeployedapplication.ear Thetabcompletionfeaturewillhelpyoutocompletethevalueforthelistof—servergroupsselectedfordeployment. Now,supposewewanttoundeploytheapplicationfromjustoneservergroup.Inthis case,therecanbetwopossibleoutcomes.Iftheapplicationisavailablejustonthatserver group,youwillsuccessfullycompletetheundeploymentasshowninthefollowing command: [domain@localhost:9990/]undeploywflyproject.war—server-groups=mainserver-group Ontheotherhand,ifyourapplicationisavailableonotherservergroups,thefollowing errorwillbereturnedbytheCLI: Undeployfailed:{“domain-failure-description”=>{“Compositeoperation failedandwasrolledback.Stepsthatfailed:”=>{“Operationstep-3”=> “Cannotremovedeploymentwflyproject.warfromthedomainasitisstill usedbyservergroups[other-server-group]”}}} Itseemsthatsomethingwentwrong.Asamatteroffact,whenyouareremovingan applicationfromaservergroup,thedomaincontrollerwillverifythatanyotherserver groupwillnotrefertotheapplication;otherwise,thepreviouscommandwillfail. Youcan,however,instructthedomaincontrollertoundeploytheapplicationwithout deletingthecontentaswell.Thisisshowninthefollowingcommand: [domain@localhost:9990/]undeployapplication.ear—server-groups=mainserver-group—keep-content CreatingCLIscripts Asaprogramdeveloper,youmightbeinterestedtoknowthataCLIcanexecute commandsinanon-interactivewaybyaddingthemtoafile,justasashellscript.Inorder toexecutethescript,youcanlaunchtheCLIwiththe—fileparameterasinthefollowing example(forWindows): jboss-cli.bat—file=test.cli TheequivalentcommandforUnixuserswillbeasfollows: ./jboss-cli.sh—file=test.cli Inthenextsection,wewilllookatsomeusefulscriptsthatcanbeaddedtoyour administratortoolbox. DeployinganapplicationtoseveralWildFlynodes TheearlierJBossASreleasesusedtoshipwithafarmfolder,whichwouldtriggera deploymenttoallthenodesthatarepartofaJBosscluster.Thisoptionisnotincluded anymorewithJBossAS7andWildFly,butresurrectingafarmdeploymentisjustamatter offollowingafewCLIinstructions. Inthefollowingexample,wearedeployinganapplicationtothedefaultserveraddress (127.0.0.1andport9990)andtoanotherserverinstancethatisboundtothesame addressbuttoport10190: connect deploy/usr/data/example.war connect127.0.0.1:10190 deploy/usr/data/example.war Restartingserversinadomain Acommonrequirementforthedomainadministratoristorestarttheapplicationserver nodes,forexample,whensomeserverlibrariesareupdated.CLIprovidesahandy shortcuttostopandstartalltheserversthatarepartofaservergroup: connect /server-group=main-server-group:start-servers /server-group=main-server-group:stop-servers Ifyoupreferamoregranularapproach,youcanstartthesingleservernodesasshownin thefollowingexample,whichshowshowyoucanapplyconditionalexecutionlogicin yourCLIscripts: connect if(result==“STARTED”)of/host=master/server-config=server-one:readattribute(name=status) /host=master/server-config=server-one:stop end-if if(result==“STARTED”)of/host=master/server-config=server-two:readattribute(name=status) /host=master/server-config=server-two:stop end-if /host=master/server-config=server-one:start /host=master/server-config=server-two:start Intheifend-ifpartofthecode,wearecheckingfortheserver’sstatusattribute.Ifthe statusisSTARTED,theapplicationserversarestoppedandthenrestarted. Installingadatasourceasamodule InWildFly,youcanusethemodulecommandinordertoinstallanewmodule.Wealready didsomethingsimilarinChapter5,CombiningPersistencewithCDI.Now,youcanfully automateadatasourcecreationasshowninthefollowingexample: connect moduleadd—name=org.postgresql—resources=postgresql-9.3-1101.jdbc41.jar —dependencies=javax.api,javax.transaction.api /subsystem=datasources/jdbc-driver=postgresql:add(driver-modulename=org.postgresql,driver-name=postgresql,driver-classname=org.postgresql.Driver) /subsystem=datasources/data-source=PostgreSQLDS:add(jndiname=java:jboss/datasources/PostgreSQLDS,driver-name=postgresql, connection-url=jdbc:postgresql://localhost:5432/ticketsystem,username=jboss,password=jboss) Thefirstlineofthescript,aftertheconnection,installsanewmodulenamed org.postgresqlinyourservermodules’directory,includingthePostgreSQLJDBC driverandtherequireddependencies. ThesecondlineinstallstheJDBCdriverfortheorg.postgresqlmoduleintothe datasources/jdbc-driversubsystem. Finally,adatasourceisaddedtojndijava:jboss/datasources/PostgreSQLDSwiththe requiredURLandcredentials. AddingJMSresources AddinganewJMSdestinationisquiteeasysinceitdoesnotrequirealengthysetof commands.However,itissometimesyourapplicationthatneedstosetuplotsofJMS destinationsinordertowork,sowhynotcreateascriptforittoo?Thefollowingisatiny scriptthataddsaJMSqueuetotheserverconfiguration: connect jms-queueadd—queue-address=queue1—entries=queues/queue1 ThefollowingisthecorrespondingscriptyoucanusetocreateaJMStopic: connect jms-topicadd—topic-address=topic1—entries=topics/topic1 Usingadvancedlanguagestocreatepowerful CLIscripts Sofar,wehavelearnedhowtowriteCLIshellcommandstomanagetheapplication server’sresources.Thisapproachhastheadvantagethatyoucaneasilyaccessevery serverresourceeasilyandquickly,thankstothebuilt-inautocompletionfeature.If,onthe otherhand,youwanttoperformsomesophisticatedlogicaroundyourcommands,then youneedtofindsomeotheralternatives. Ifyouareashellguru,youmighteasilyresorttosomebashscriptinginordertocapture theoutputoftheCLIandusetherichsetofUnix/Linuxtoolstoperformsome administrativeactions. Supplyingashortoverviewofthebashfunctionalitiesmightbeanamusingexercise; however,ifwedothis,wewouldmoveawayfromthescopeofthisbook.Wewillinstead documentsomebuilt-infunctionalitiessuchasthefollowing: Inthefirstsection,wewillshowhowtouseaCLIremoteclientAPIfromwithina Pythonscript Inthenextsection,wewillusetherawmanagementAPItoexecuteCLIcommands fromwithinJavaapplications TherearemultipleusecasesinwhichtheJBossCLIscriptscouldbeuseful.Ascriptcould beusedtoconfigureadeveloper’smachine,atestenvironment,orasaninitial configurationforproduction.Inmanycases,theconfigurationneededtostartafull-blown enterpriseapplicationmaybenontrivial;youmightneedtouseaspecificport configurationtoclustertestsoryourownsecuritydomain.Youmightalsoneedyour continuousintegrationservertodothisforyou.Besidesthis,it’sbettertohavean automaticconfigurationscriptthansetuptheconfigurationmanuallyeverytime,whichis justawasteoftimeandapotentialsourceofbugs. UsingscriptinglanguagestowrapCLIexecution JBossAS7hasintroducedanewCLIremoteAPIthatactsasafacadefortheCLIpublic API.ThecoreclassthatactsasabridgebetweenthesetwoAPIsisthe scriptsupport.CLIclassthatiscontainedintheJBOSS_HOME/bin/client/jboss-cliclient.jarfile. ThankstothisAPI,youcanexecuteCLIcommandsusinglotsofdifferentlanguagessuch asJython,Groovy,orJavaScript.SinceJythonisalsothedefactomanagementstandard forotherapplicationservers,suchasOracle,WebLogic,andWebSphere,wewilluseitto performsomebasicmanagementtasks. Note JythonisanimplementationofPythonforJVM.Jythonisextremelyusefulbecauseit providestheproductivityfeaturesofamaturescriptinglanguagewhilerunningonaJVM. UnlikeaPythonprogram,aJythonprogramcanruninanyenvironmentthatsupportsa JVM. Jythonisinvokedusingthejythonscript,whichisashortscriptthatinvokesyourlocal JVM,runningtheJavaclassfile,org.python.util.jython. ThefirstthingyouneedtodoinordertogetstartedisdownloadtheJythoninstallerfrom http://www.jython.org/downloads.html. Runtheinstallerwiththefollowingcommand: java-jarjython-installer-2.5.3.jar Next,addtheJYTHON_HOME/binfolder(forexample,C:\jython2.5.3\bin)tothesystem pathandaddthejboss-cli-client.jarfiletothesystem,CLASSPATH.Forexample,in Windows,usethegivencommand: setJYTHON_HOME=C:\jython2.5.3 setPATH=%PATH%;%JYTHON_HOME%\bin setCLASSPATH=%CLASSPATH%;%JBOSS_HOME%\bin\client\jboss-cli-client.jar;. Here’sthesamecommandforLinux: exportPATH=$PATH:/usr/data/jython2.5.3/bin exportCLASSPATH=$CLASSPATH$:%JBOSS_HOME%/bin/client/jboss-cli-client.jar Ok,nowwewillcreateourfirstscriptthatwillbasicallyreturntheJNDIviewofour applicationserver. Note BeawarethatJython,justlikePython,usesindentationtodeterminethecodestructure insteadofusingbracesorkeywords.Therefore,donotusethemrandomly.AnIDEmight helpyouwiththis—forPythonyoucanuse,forexample,Vimwithpython-mode (https://github.com/klen/python-mode)orEclipsewiththePyDevextension (http://pydev.org/). Createafilenamedscript.pycontainingthefollowingcode: fromorg.jboss.as.cli.scriptsupportimportCLI cli=CLI.newInstance() cli.connect() cli.cmd(“cd/subsystem=naming”) result=cli.cmd(“:jndi-view”) response=result.getResponse() print‘JNDIVIEW=======================‘ printresponse cli.disconnect() Nowexecutethescriptwiththefollowingcode: jythonscript.py Asyoucansee,thecodeisveryself-explanatory;weareimportingthe org.jboss.as.cli.scriptsupport.CLIclass,whichisusedtosendcommandsandread theresponse.Then,weareconnectingtothelocalWildFlyinstanceandissuinga:jndiviewcommand. Note TheconnectcommandcanbeusedtoconnecttoaremoteWildFlyhostaswellbyadding thefollowingparameters:connect(StringcontrollerHost,intcontrollerPort, Stringusername,Stringpassword). Theresponsevariableisorg.jboss.dmr.ModelNode.Thiscanbefurtherinspectedas showninthefollowingexample,whichgoesintosomedepthaboutplatformMBeans,to getsomememorystatistics: fromorg.jboss.as.cli.scriptsupportimportCLI cli=CLI.newInstance() cli.connect() cli.cmd(“cd/core-service=platform-mbean/type=memory/”) result=cli.cmd(“:read-resource(recursive=false,proxies=false,includeruntime=true,include-defaults=true)”) response=result.getResponse() enabled=response.get(“result”).get(“heap-memory-usage”) used=enabled.get(“used”).asInt() ifused>512000000: print“Over1/2GbMemoryusage“ else: print‘Lowusage!’ cli.disconnect() Inthepreviousexample,wetrackedtheresourcescontainedin/coreservice=platform-mbean/type=memory.Theavailableresourcesare,however,child resourcesofthetwokindsofavailableheapmemoryareas(heap-memory-usageandnonheap-memory-usage),asshownbythefollowingcode: [standalone@localhost:9990/]/core-service=platformmbean/type=memory:read-resource(recursive=false,proxies=false,includeruntime=true,include-defaults=true) { “outcome”=>“success”,“result”=>{ “heap-memory-usage”=>{“init”=>67108864L,“used”=> 59572256L,“committed”=>170852352L,“max”=>477233152L}, “non-heap-memory-usage”=>{ “init”=>24313856L,“used”=>90491328L,“committed”=> 90701824L,“max”=>369098752L}, “object-pending-finalization-count”=>0,“verbose”=>false } } UsingjustthegetcommandoftheModelNodeobject,youcanrefertothechildresources ofthememorytypeandreachallthesingleattributes.Onceyouhavegottheattributes, it’seasytocastthemtoanintegerusingtheasInt()functionoftheModelNodeobjectand usethecoolPythonconstructstoalertyouradministrator. UsingtherawmanagementAPItomanage theapplicationserver Ifyoudon’tfeellikelearningascriptinglanguagetomanagetheapplicationserver,you canstillusetherawmanagementAPIfromwithinyourJavaclasses.Don’tbeinfluenced bythefactthatweleftthisoptionasthelastone;infact,usingthenativemanagement APIisnotdifficultatallsinceitisbasedonveryfewclassesandhaslittlecompile-time andruntimedependenciesontheWildFlyAPI. Forthisreason,youcanusethemanagementAPIaswellfromanyJavaEEapplicationby simplyaddingthefollowingdependenciestotheMETA-INF/MANIFEST.MFfileofyour application: Dependencies:org.jboss-as-controller-client,org.jboss.dmr ThecoreAPInameddetypedmanagementAPIisquitesimple;theprimaryclassis org.jboss.dmr.ModelNode,whichwealreadymentionedintheJythonsection.A ModelNodeclassisessentiallyjustawrapperaroundavalue;thevalueistypicallyabasic JDKtypethatcanberetrievedusingthegetType()methodofModelNode. Inadditiontothejboss-dmrAPI,theothermodulethatisusedtoconnecttothe managementAPIisjboss-as-controller-client. Note Youdon’tneedtodownloadanyoftheselibrariessincebothofthesemodulesare includedintheapplicationserversincerelease7. Readingmanagementmodeldescriptionsviatheraw managementAPI UsingthedetypedmanagementAPIisnottoodifferentfromitsscriptinglanguage counterpart;atfirst,youneedtocreateamanagementclientthatcanconnecttoyourtarget process’snativemanagementsocket(whichcanbeanindividualstandalonemodeserver, orinadomainmodeenvironment,thedomaincontroller): ModelControllerClientclient= ModelControllerClient.Factory.create(InetAddress.getByName(“localhost”), 9990); Next,youneedtocreateanoperationrequestobjectusingtheorg.jboss.dmr.ModelNode class,asshowninthefollowingcommand: finalModelNodeoperation=newModelNode(); operation.get(“operation”).set(“jndi-view”); finalModelNodeaddress=operation.get(“address”); address.add(“subsystem”,“naming”); operation.get(“recursive”).set(true); operation.get(“operations”).set(true); finalModelNodereturnVal=client.execute(operation); logger.info(returnVal.get(“result”).toString()); Asyoucansee,ModelNodeobjectscanbechainedinordertoreachanoperation(inthe example,theJNDIview),whichisavailableonanodepath(inourcase,thenaming subsystem). OnceyouhaveaddedtheModelNodeattributes,youcanissuetheexecutecommandson yournode,whichwillinturnreturnModelNodewheretheresultoftheoperationwillbe stored. Inthesamples,youcanfindafullyworkingprojectcontainingthesemanagement examples. CreatingyourresourcewatchesusingthedetypedAPI NowthatyouhavelearnedthebasicsofthedetypedmanagementAPI,wewillillustrate aconcreteexample;ourgoalwillbetomonitoraserverresource(thenumberofactive JDBCconnectionsforadatasource)usinganEJB.Youcanusethispatterntocreateyour ownserverwatchesthatcanbeintegratedwithyourapplicationenvironment.Thisis showninthefollowingcodesnippet: packagecom.packtpub.wflydevelopment.chapter9; importorg.jboss.as.controller.client.ModelControllerClient; importorg.jboss.dmr.ModelNode; importjavax.ejb.Schedule; importjavax.ejb.Stateless; importjava.io.Closeable; importjava.net.InetAddress; importjava.util.logging.Level; importjava.util.logging.Logger; @Stateless publicclassWatchMyDB{ privatefinalstaticLoggerlogger= Logger.getLogger(WatchMyDB.class.getName()); @Schedule(dayOfWeek=“*”,hour=“*”,minute=“*”,second= “*/30”,year=“*”,persistent=false) publicvoidbackgroundProcessing(){ ModelControllerClientclient=null; try{ client= ModelControllerClient.Factory.create(InetAddress.getByName(“localhost”), 9990); finalModelNodeoperation=newModelNode(); operation.get(“operation”).set(“read-resource”); operation.get(“include-runtime”).set(true); finalModelNodeaddress=operation.get(“address”); address.add(“subsystem”,“datasources”); address.add(“data-source”,“ExampleDS”); address.add(“statistics”,“pool”); finalModelNodereturnVal=client.execute(operation); finalModelNodenode2=returnVal.get(“result”); finalStringstringActiveCount= node2.get(“ActiveCount”).asString(); if(stringActiveCount.equals(“undefined”)){ return;//Connectionunused } intactiveCount=Integer.parseInt(stringActiveCount); if(activeCount>50){ alertAdministrator(); } }catch(Exceptionexc){ logger.log(Level.SEVERE,“Exception!”,exc); }finally{ safeClose(client); } } publicvoidsafeClose(finalCloseablecloseable){ if(closeable!=null){ try{ closeable.close(); }catch(Exceptione){ logger.log(Level.SEVERE,“Exceptionclosingtheclient!“, e); } } } privatevoidalertAdministrator(){ //Implementit! } } WewillnotrehashthebasicconceptsaboutEJBTimers,whichhavebeendiscussedin Chapter3,IntroducingJavaEE7–EJBs.Wesuggestthatyouhavealookatthe highlightedsectionofthecode,whichshowshowyoucanchainyourModelNodeobjects inordertoreachtheattributethatwearegoingtomonitor(theactiveCountattributeof theExampleDSdatasource). OnceyouhavethevalueoftheactiveCountattribute,weleaveittoyourimaginationto envisionallthepossibleactionsyoucanundertake! ItisworthnotingthatthereareadditionalmeansofmonitoringWildFly.Oneofthemis usingthehawt.iopluginforJBoss(http://hawt.io/plugins/jboss/).Wealreadytriedthisfor ActiveMQwhenweweredevelopingMessageBeans.AnothertoolisJolokia (http://www.jolokia.org/),whichexposesJMXbeansoverHTTP.So,ifyouarenotinto writingyourownmonitors,thereareotheroptionsworthexploring. Role-basedsecurity InJBoss7,alogged-inadministratorhasunlimitedpowerovereveryconfigurationaspect ofarunningserver.Thiscouldbeaprobleminaproductionenvironmentwhenmultiple usershaveaccesstotheservertododifferenttasks.Oneusercouldonlybeinterestedin deployingnewapplications,anothershouldonlybeabletorestarttheserver,andthere couldbeonewhoshouldnotbeabletochangeanything(forexample,amonitoringagent sendingdataabouttheexecutionofanapplication). Tosupportthesekindsofrequirements,WildFlybringstwoaccesscontrolstrategies: Simple,whichistheall-or-nothingapproachknownfromJBossAS7andEAPin versionsearlierthan6.2(everyauthenticatedadministratorhasfullaccesstothe applicationserver).Thisisthedefaultstrategy. Rolebasedaccesscontrol(RBAC),whichallowsyoutoassignadministrativeusers tospecificmanagementroles. Let’snavigatetohttp://localhost:8080/consoleandloginwithouradministrator password.TheuppermenucontainsatabnamedAdministration.Thisisusedto configuretheaccesscontrolmechanism.Onceyouclickonit(youshouldseeamessage boxinformingyouthatRBACisnotyetenabled),wewillseethreesubtabs:Users, Groups,andRoles.Let’stakeacloserlookateachoftheseobjects. Usersaredefinedusingtheadd-user.bat(.sh)scriptsintheJBOSS_HOME/bindirectory. WehavealreadydefinedonebeforethefirsttimeweaccessedtheJBossconsole.The createduser,however,requiressomeadditionalinformationinordertodeterminehisor hersecuritylevel.Theeasiestwaytoachievethisistoorganizethemintogroups.The assignmentcanbedoneviatheusercreationscriptsorbythemgmt-groups.properties filesintheWildFly’sconfigurationdirectory.Anotherwaytodothisistodefineasecurity realmconnectedtoanexternalsource(anLDAPserverforinstance).Wewilltalkmore aboutsecurityrealmsinthenextchapter.Fornow,youcancreateauserassignedtoa groupnamedTestGroup. Agroupismappedtoasetofsecurityrolestoprovidespecificpermissions.Forexample, wecancreateusergroupsfordevelopersandjunioradministratorsandmapthemtoa subsetofdesiredroles.Ausercanbepartofmultiplegroups,sothereisalsoapossibility toexcludearoleforaspecificgroupsothatnoothergroupcouldgrantit. Finally,wehaverolesthatcovermultipleareasoftheserver’sfunctionality.Everyrole hasasetofpermissionsassignedandsomeofthemareadditionallyconstrained(for instance,toallowyoutoconfiguremodificationsinonlyspecificsubsystemssuchasdata sources).Alistofbuilt-inrolesisavailableinthefollowingtable: Role Permissions Sensitivedata(passwordsandauditing) Monitor Read-onlyaccesstoconfigurationandruntimestate. Noaccess. Operator AllpermissionsofMonitor.Thisrolecanrestarttheserver,controlJMSdestination,anddatabaseconnectionpools.Itcannotmodifytheconfiguration. Noaccess. Maintainer AllpermissionsofOperator.Thisrolecanmodifytheconfiguration(includingdeployingnewapplications). Noaccess. Deployer AllpermissionsofMaintainer,butwithrestrictionsondeployingnewapplications(cannotchangetheconfigurationoftheserver). Noaccess. Administrator AllpermissionsofMaintainer. Read/writeaccess.Noaccesstotheaudit system. Auditor AllpermissionsofMonitor. Read-onlyaccess.Fullaccesstotheauditing system. SuperUser Everythingispermitted.TheadministratorknownfromJBossAS7andthesimplestrategyinWildFly.Also,thisisthedefaultroleforalocaluser (connectingfromalocalhost). Fullaccess. Besidesrelyingonthegroup-rolemappingmechanism,youhaveanotheroptiontoassign userstoroles.YoucanusetheAdministration/Usersscreenintheadminconsoleto directlyassignausertoarole(besuretoselectIncludeasthetype).Assignthe SuperUserrolenowtoyourcurrentuserusingtheAddbutton.Additionally,youcanuse Administration/GroupstoaddournewlycreatedTestGroupto,forinstance,theMonitor role. Ourconfigurationisnowinplace;tryandcheckitout.ToswitchtotheRBACstrategy, wewillneedtoissuethefollowingcommandusingtheCLIinterface: /core-service=management/access=authorization:writeattribute(name=provider,value=rbac) Reloadtheserverandlogintothewebconsoleagainusingtheaccountyoudesignedas SuperUser. Note Wearetestingthewebconsole,buttheRBACmechanismalsoworksfortheCLI.Note thattheCLIwillallowyoutoaccessitfromlocalhostaslongasyouhavethe$local userallowedinyoursecurityrealm: <security-realmname=“ManagementRealm”> <authentication> <localdefault-user=”$local”allowed-users=”*”/> <propertiespath=“mgmt-users.properties”relativeto=“jboss.server.config.dir”/> </authentication> <authorizationmap-groups-to-roles=“false”> <propertiespath=“mgmt-groups.properties”relativeto=“jboss.server.config.dir”/> </authorization> </security-realm> Ifyouwishtodisableit,simplyremovethisline. Ifyouarewonderingwhatyourcurrentroleis,youcanclickonUsernameintheupperrightcornerofthescreen.Youshouldseeabitofinformationaboutthecurrentlyloggedinadministratorinthefollowingscreenshot: Intheprecedingscreenshot,wecanseethattheuserrootisloggedinasaSuperUserrole. Besideshavingthepossibilitytodoeverythingwiththeapplicationserver,theSuperUser rolehasoneadditionalfeature.ItcanimpersonateotherrolesusingRunas…,whichcan beusefulifyouwanttocheckwhatarethelimitationsofanotherrole.Feelfreetocheck themoutrightnow.Forinstance,asaMonitor,youshouldnotbeabletoalteranysettings intheadminconsole. Youcanalsoreloginwiththeuseryou’vecreatedearlier,whichisassignedtoTestGroup. ItshouldhavetheMonitorroleshownintheupper-rightcornerofthescreen. Auditingadministrativeoperations WildFlyintroducesanaudit-logfeaturethatallowstheadministratorstotrackthe configurationchangesmadeontheserver.Thefeatureisinitiallydisabledbutcanbe usefulinsomescenarios,solet’stakeashortlookatit. Theaudit-logconfigurationconsistsofthreeparts: Formatter:Thisformatsthelogoutput.Bydefault,it’sbasedonJSON. Handler:Thishandlestheoutput.Bydefault,itisafile-basedhandler,butitis possibletouseaTCPorUDPtosendthelogstoaremoteserver. Logger:Thiscontrolstheloginprocess. DetailedconfigurationcanbefoundintheofficialWildFlydocumentationat https://docs.jboss.org/author/display/WFLY8/Audit+logging. Theauditlogisdisabledbydefault.Toenableit,wemustissuethefollowingCLI command: /core-service=management/access=audit/logger=audit-log:writeattribute(name=enabled,value=true) Nowyoucantrytodoanyadministrativeactionusingthewebconsole(forinstance, disablingadatasource).Afterthis,youshouldfindatraceofitin JBOSS_HOME/standalone/data/audit-log.log(alongwithinformationaboutswitching theauditloggingon). Patchingarunninginstance ThenewestversionoftheJBossApplicationServercomeswithapatchingutilitythat allowsyoutoautomaticallyupdatepartsoftheserverwithnewerversions.Currently,the patchingisdoneusingaCLI.Anypatchcanbereverted,andtheadministratorisableto trackthehistoryofpatches. Apatchcanbeappliedbysimplycallingthepatchapply<filepath>(without-) command.Acomplementarycommandispatchrollback—patch-id=id,apatchrollbackcommand.Toobtaininformationabouttheinstalledpatches,simplycallpatch info.PatchesaredistributedbyteamsresponsibleforspecificWildFlysubsystems.Visit theirwebsitesifyouneedapatchforaspecificmodule. Summary Inthischapter,wecoveredtheapplicationserver’smanagementAPIfromadeveloper’s perspective,whichwillenableyoutowriteyourownscriptstomonitorthehealthofyour applicationserver. Themosteffectivetoolformonitoringtheapplicationserveristhecommand-line interface.However,ifyouwanttospiceitupwithsometypicalprogramminglogic,you canresorttosomeotheralternativessuchasscriptinglanguagesortherawmanagement API. Wealsoexploredsomeofthenew,advancedfeaturesthatwereintroducedwithWildFly. Younowknowhowtorestrictaccesstoyourmanagementconsoleandhowtoauditthe changesdonetotheconfiguration. Wehavenowcompletedourreviewofmanagement.Inthenextchapter,wearegoingto discussclustering,whichistheenvironmentwherecriticalapplicationsaredeployed. Chapter10.SecuringWildFlyApplications Inthepreviouschapter,wedescribedhowtomanageyourapplicationserver.Thenext stopinourjourneywillbelearningaboutsecurity,whichisakeyelementofany Enterpriseapplication.Youmustbeabletocontrolandrestrictwhoispermittedtoaccess yourapplicationsandwhatoperationsusersmayperform. TheJavaEnterpriseEditionspecificationdefinesasimplerole-basedsecuritymodelfor EnterpriseJavaBeansandwebcomponents.TheimplementationofWildFlysecurityis deliveredbythePicketboxframework(formerlyknownasJBossSecurity),whichispart oftheapplicationserverandprovidestheauthentication,authorization,auditing,and mappingcapabilitiesforJavaapplications. Hereisthelistoftopicswewillcoverinthischapter: AshortintroductiontotheJavasecurityAPI ThefoundationoftheWildFlysecuritysubsystem DefiningandapplyingloginmodulestosecureJavaEEapplications UsingtheSecureSocketsLayer(SSL)protocoltoencryptthetraffic ApproachingtheJavasecurityAPI JavaEEsecurityservicesprovidearobustandeasilyconfigurablesecuritymechanismto authenticateusersandauthorizeaccesstoapplicationfunctionsandtheassociateddata.To betterunderstandthetopicsrelatedtosecurity,weshouldfirstlayoutsomebasic definitions: Authentication:Thisistheprocessbywhichyoucanverifywhoiscurrently executinganapplication,regardlessofwhetheritisanEJBoraservlet(andsoon). AuthenticationisusuallyperformedbymeansofaLoginmodulecontainedina web/standaloneapplication.TheJavaEEspecificationprovidesonlygeneral requirementsthatmustbemetbyallcompliantcontainers.Thismeansthatevery applicationserverprovidesitsownauthenticationmechanisms,whichisaproblem whenitcomestoportabilityofapplicationsandtheirconfiguration. Authorization:Thisistheprocessbywhichyoucanverifyifauserhastheright (permission)toaccesssystemresourcesorinvokecertainoperations.Authorization, therefore,presupposesthatauthenticationhasoccurred;itwouldbeimpossibleto grantanyaccesscontrolifyoudon’tknowwhotheuserisfirst.JavaEEspecification providesmeanstoauthorizeauser’sactions.Theauthorizationdeclarationsare usuallyportablebetweendifferentapplicationservers.Thedifferencebetween authenticationandauthorizationisdepictedinthefollowingdiagram: InJavaEE,thecontainersareresponsibleforprovidingapplicationsecurity.Acontainer basicallyprovidestwotypesofsecurity:declarativeandprogrammatic.Let’stakealook atbothofthem: Declarativesecurity:Thisexpressesanapplicationcomponent’ssecurity requirementsbymeansofdeploymentdescriptors.Becausedeploymentdescriptor informationiscontainedinanexternalfile,itcanbechangedwithouttheneedto modifythesourcecode. Forexample,EnterpriseJavaBeanscomponentsuseanEJBdeploymentdescriptor, whichmustbenamedejb-jar.xmlandplacedintheMETA-INFfolderoftheEJB JARfile. Webcomponentsuseawebapplicationdeploymentdescriptornamedweb.xml, whichislocatedintheWEB-INFdirectory. Tip SincethereleaseofJavaEE5,youcanapplydeclarativesecuritybymeansof annotationsjustlikewehaveforotherkeyAPIs(EJB,webservices,andsoon). Annotationsarespecifiedwithinaclassfile,andwhentheapplicationisdeployed, theapplicationservertranslatesthisinformationinternally. Programmaticsecurity:Thisisembeddedinanapplicationandusedtomake securitydecisions.Itcanbeusedwhendeclarativesecurityaloneisnotsufficientto expressthesecuritymodelofanapplication.TheJavaEEsecurityAPIallowsthe developertotestwhetherornotthecurrentuserhasaccesstoaspecificrole,using thefollowingcalls: isUserInRole()forservletsandJSPs(adoptedin javax.servlet.http.HttpServletRequest) isCallerInRole()forEJBs(adoptedinjavax.ejb.SessionContext) Additionally,thereareotherAPIcallsthatprovideaccesstotheuser’sidentity, whichareasfollows: getUserPrincipal()forservletsandJSPs(adoptedin javax.servlet.http.HttpServletRequest) getCallerPrincipal()forEJBs(adoptedinjavax.ejb.SessionContext) UsingtheseAPIs,youcandeveloparbitrarilycomplexauthorizationmodels. TheWildFlysecuritysubsystem WildFlysecurityqualifiesasanextensiontotheapplicationserverandisincluded,by default,bothinstandaloneanddomainserversusingthefollowingcode: <extensionmodule=“org.jboss.as.security”/> WildFlydefinessecuritypoliciesusingtwoterms:securityrealmsandsecuritydomains. Securityrealmsareconfigurationsetsmappedtoexternalconnectors(forexample,EJB remotingandmanagementinterface).Theyalloweveryconnectiontypetohaveitsown appropriateauthenticationandauthorizationpropertiesdefined.Forinstance,both managementandapplicationrealmsdefinetwoseparatefiles,whichstoretheallowed usernames.Additionally,theapplicationrealmcontainsareferencetoafilethatdefines userrole. Theconfigurationdefinedinthesecurityrealmisthenpassedtoasecuritydomain requestedbythedeployedapplication.Thesecuritydomaindefinesasetofloginmodules thatareresponsibleforcheckingtheuser’scredentialsandcreatingasecurityprincipal representingtheclient(alongwithasetofrolesfortherequester). Thefollowingisanextractfromthedefaultsecuritysubsystemcontainedintheserver configurationfile,whichcontainstheRealmDirectloginthatwillbeusedinthenext sectiontosecuretheTicketexampleapplication: <subsystemxmlns=“urn:jboss:domain:security:1.2”> <security-domains> <security-domainname=“other”cache-type=“default”> <authentication> <login-modulecode=“Remoting”flag=“optional”> <module-optionname=“password-stacking” value=“useFirstPass”/> </login-module> <login-modulecode=“RealmDirect”flag=“required”> <module-optionname=“password-stacking” value=“useFirstPass”/> </login-module> </authentication> </security-domain> <security-domainname=“jboss-web-policy”cache-type=“default”> <authorization> <policy-modulecode=“Delegating”flag=“required”/> </authorization> </security-domain> <security-domainname=“jboss-ejb-policy”cache-type=“default”> <authorization> <policy-modulecode=“Delegating”flag=“required”/> </authorization> </security-domain> </security-domains> </subsystem> Configurationfilesaredefinedinthesecurityrealmusingthefollowingcode: <security-realmname=“ApplicationRealm”> <authentication> <localdefault-user=”$local”allowed-users=”*”/> <propertiespath=“application-users.properties”relativeto=“jboss.server.config.dir”/> </authentication> <authorization> <propertiespath=“application-roles.properties”relativeto=“jboss.server.config.dir”/> </authorization> </security-realm> Asyoucansee,theconfigurationisprettyshortasitrelieslargelyondefaultvalues, especiallyforhigh-levelstructuressuchasthesecuritymanagementarea.Bydefining yourownsecuritymanagementoptions,youcould,forexample,overridethedefault authentication/authorizationmanagerswithyourimplementations.Sinceitislikelythat youwillnotneedtooverridetheseinterfaces,wewillratherconcentrateonthesecuritydomainelement,whichisthecoreaspectofWildFlysecurity. AsecuritydomaincanbethoughtofasaCustomsOfficeforforeigners.Beforethe requestcrossesWildFlyborders,thesecuritydomainperformsalltherequired authenticationandauthorizationchecksandeventuallynotifiesifhe/shecanproceedor not. Securitydomainsaregenerallyconfiguredatserverstartupandsubsequentlyboundinto theJNDItreeunderthekeyjava:/jaas/.Withinthesecuritydomain,youcanconfigure loginauthenticationmodulessothatyoucaneasilychangeyourauthenticationprovider bysimplychangingitslogin-moduleelement. Thereareseveralimplementationsofloginmodulesavailableoutofthebox;thereis obviouslynotenoughroomheretodescribeindetailthefeaturesofeachmodule,though wewillofferacomprehensivedescriptionofsomepopularoptions,suchas: TheRealmDirectloginmodule,whichcanbeusedforbasicfile-basedauthentication TheDatabaseloginmodule,whichchecksusercredentialsagainstarelational database Note Shouldyouneedfurtherinformationaboutloginmodules,checkouttheWildFly documentationat: https://docs.jboss.org/author/display/WFLY8/Security+subsystem+configuration https://docs.jboss.org/author/display/WFLY8/Security+Realms Settingupyourfirstloginmodule Inthefollowingsection,wewilldemonstratehowtosecureanapplicationusingthe RealmDirectsecuritydomain,whichwasintroducedearlier.TheRealmDirectlogin moduleisbasedonthefollowingtwofiles: application-users.properties:Thiscontainsthelistofusernamesandpasswords application-roles.properties:Thiscontainsthemappingbetweentheusersand theirroles Thesefilesarelocatedintheapplicationserverconfigurationfolderandtheyareupdated eachtimeyouaddanewuserviatheadd-user.sh/add-user.cmdscript.Forourpurpose, wewillcreateanewapplicationusernameddemouser,whichbelongstotheroleManager, asshowninthefollowingscreenshot: Oncetheuserisadded,theapplication-users.propertiesfilewillcontainthe usernameandtheMD5encodingofthepassword,shownasfollows: demouser=9e21f32c593ef5248e7d6b2aab28717b Conversely,theapplication-roles.propertiesfilewillcontaintherolesgrantedtothe demouserusernameonceloggedin: demouser=Manager UsingtheloginmoduleintheTicketwebapplication WecannowapplytheRoleDirectloginmoduleintheTicketwebapplicationdescribed inChapter4,LearningContextandDependencyInjection(youcouldpicktheversion fromanotherchapterifyoulike).WewillfirstshowhowtoprovideaBASICweb authentication,andthenwewillshowaslightlymorecomplexexampleusingFORMbasedauthentication. Note BASIC-accessauthenticationisthesimplestwaytoprovideausernameandpassword whenmakingarequestthroughabrowser. Itworksbysendinganencodedstringcontainingtheusercredentials.ThisBase64encodedstringistransmittedanddecodedbythereceiver,resultingincolon-separated usernameandpasswordstrings.Whenitcomestosafety,BASICauthenticationisusually notthebestsolution.Thepasswordcanbestolenduringthetransmission,soSSLisa mustinordertoprotectit. Turningonwebauthenticationrequiresthesecurity-constraintselementtobedefined inthewebapplicationconfigurationfile(web.xml),asshowninthefollowingcode snippet: <web-appxmlns=“http://xmlns.jcp.org/xml/ns/javaee” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd” version=“3.1”> …… <security-constraint> <web-resource-collection> <web-resource-name>HtmlAuth</web-resource-name> <description>applicationsecurityconstraints </description> <url-pattern>/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>Manager</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> </login-config> <security-role> <role-name>Manager</role-name> </security-role> </web-app> ThisconfigurationwilladdasecurityconstraintonanyJSP/servletofthewebapplication thatwillrestrictaccesstousersauthenticatedwiththeroleManager.Allloginmodules shownintheearliersectiondefinethisrole,soyoucanjustusetheloginmodulethatsuits yourneedsbest. FromJavaEE7,therearetwomoremethodstoexpressyoursecurityconstraints.Firstly, youcanuseanewcontainerprovidedrole:**.Itindicatesthatyouarereferringtoany authenticateduser,withouttakingitsrolesintoaccount. Thesecondoneisthedeny-http-uncovered-methodstag,whichcanbeusedina web.xmlfiletoforbidaccesstoeveryHTTPmethodthatisnotcoveredbyaseparate securityconstraint. ThenextconfigurationtweakneedstobeperformedontheJBosswebdeployment’s descriptor,WEB-INF/jboss-web.xml.Youneedtodeclarethesecuritydomainhere,which willbeusedtoauthenticatetheusers.SinceweareusingRealmDirect,whichispartof theotherbuilt-inloginmodule,wewillneedtoincludethejava:/jaas/othercontext information: <jboss-web> <security-domain>java:/jaas/other</security-domain> </jboss-web> ThefollowingdiagramillustratesthewholeconfigurationsequenceappliedtoaDatabase loginmodule: Onceyouhavedeployedyourapplication,theoutcomeshouldbeablockingpopup requestinguserauthentication.Thewindowwilllookalittledifferentoneverybrowser anditsappearancecannotbechanged. Logginginwithdemouserusernameandthevalidpasswordwillgrantaccesstothe applicationwiththeManagerrole. SwitchingtoFORM-basedsecurity FORM-basedauthenticationletsdeveloperscustomizetheauthenticationuserinterface, adaptingit,forexample,toyourcompany’sstandards.Configuringitinyourapplication requiresyoutobasicallymodifyjustthelogin-configstanzaofthesecuritysectionof yourweb.xmlfile.Withinit,wewilldefinealoginlandingpage(login.xhtml)andan errorpage(error.xhtml),incasetheloginfails.Thecodesnippetforitisasfollows: <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/faces/login.xhtml</form-login-page> <form-error-page>/faces/error.xhtml</form-error-page> </form-login-config> </login-config> Theloginformmustcontainfieldstoenterausernameandpassword.Thesefieldsmust benamedj_usernameandj_password,respectively.Theauthenticationformshouldpost thesevaluestothej_security_checklogicalname.Allthesenamesbeginningwithj_ arestandardizedbytheJavaServletspecification—wejustneedtofollowtheconvention inordertolettheautomaticmechanismswork.Here’sasimplelogin.xhtmlpage,which canbeusedtopasstherequiredvaluestothesecuritysystem: <?xmlversion=‘1.0’encoding=‘UTF-8’?> <!DOCTYPEhtmlPUBLIC“-//W3C//DTDXHTML1.0Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <htmlxmlns=“http://www.w3.org/1999/xhtml” xmlns:h=“http://xmlns.jcp.org/jsf/html”> <head> <title>FORMbasedLogin</title> </head> <body> <formmethod=“post”action=“j_security_check”name=“loginForm”> <h:panelGridcolumns=“2”> <h:outputLabelid=“userNameLabel”for=“j_username” value=“Username:”/> <h:inputTextid=“j_username”autocomplete=“off”/> <h:outputLabelid=“passwordLabel”for=“j_password” value=“Password:”/> <h:inputSecretid=“j_password”autocomplete=“off”/> <div/> <h:panelGroup> <h:commandButtontype=“submit”value=“Login”/> <h:commandButtontype=“reset”value=“Clear”/> </h:panelGroup> </h:panelGrid> </form> </body> </html> Forthesakeofbrevity,wewon’tincludetheerrorpage,whichwillsimplyalertthatthe userenteredanincorrectcombinationofusernameandpassword.Theexpectedoutcome isthefollowingloginscreen,whichwillinterceptalluseraccesstoyourapplicationand grantaccesstothedefaulthomepageiftheusernameandpasswordcredentialsare correct. CreatingaDatabaseloginmodule TheUserRolesloginmoduleisagoodstartingpointtolearnhowtoputtogetherallthe piecesrequiredtosecureawebapplication.Inreal-worldcases,therearebetter alternativestoprotectyourapplications,suchastheDatabaseloginmodule.Adatabase securitydomainfollowsthesamelogicexposedintheearlierexample;itjuststoresthe credentialswithinthedatabase.Inordertorunthisexample,wewillrefertoadatasource definedinChapter5,CombiningPersistencewithCDI(boundattheJNDIname java:jboss/datasources/wflydevelopment),whichneedstobedeployedonthe applicationserver: <security-domainname=“dbdomain”cache-type=“default”> <authentication> <login-modulecode=“Database”flag=“required”> <module-optionname=“dsJndiName”value=” java:jboss/datasources/wflydevelopment”/> <module-optionname=“principalsQuery”value=“selectpasswdfrom USERSwherelogin=?”/> <module-optionname=“rolesQuery”value=“selectrole‘Roles’ fromUSER_ROLESwherelogin=?”/> </login-module> </authentication> </security-domain> Inordertogetthisconfigurationworking,youhavetofirstcreatetherequiredtablesand insertsomesampledatainitusingthefollowingqueries: CREATETABLEUSERS(loginVARCHAR(64)PRIMARYKEY,passwdVACHAR(64)); CREATETABLEUSER_ROLES(loginVARCHAR(64),roleVARCHAR(32)); INSERTintoUSERSvalues(‘admin’,‘admin’); INSERTintoUSER_ROLESvalues(‘admin’,‘Manager’); Asyoucansee,theadminuserwillmapagaintotheManagerrole.Onecaveatofthis configurationisthatitusescleartextpasswordsinthedatabase;sobeforerollingthis moduleintoproduction,youshouldconsideraddingadditionalsecuritytoyourlogin module.Let’sseehowtodothisinthenextsection. Encryptingpasswords Storingpasswordsinthedatabaseasacleartextstringisnotconsideredagoodpractice; asamatteroffact,adatabasehasevenmorepotentialsecurityholesthanaregular filesystem.Imagine,forexample,thataDBAaddedapublicsynonymforsometables, forgettingthatoneofthosetablesheldsensitiveinformationsuchasapplication passwords,asshowninthefollowingscreenshot!Youthenneedtobesurethatno potentialattackerswilleverbeabletodeliverthefollowingquery. Fortunately,securingapplicationpasswordsisrelativelyeasy;youcanaddafewextra optionstoyourloginmodule,specifyingthatthestoredpasswordsareencryptedusinga messagedigestalgorithm.Forexample,intheDatabaseloginmodule,youshouldaddthe followinghighlightedoptionsatthebottom: <login-modulecode=“Database”flag=“required”> <module-optionname=“dsJndiName” value=“java:jboss/datasources/wflydevelopment”/> <module-optionname=“principalsQuery”value=“selectpasswdfromUSERS wherelogin=?”/> <module-optionname=“rolesQuery”value=“selectrole,‘Roles’from USER_ROLESwherelogin=?”/> <module-optionname=“hashAlgorithm”value=“SHA-256”/> <module-optionname=“hashEncoding”value=“BASE64”/> </login-module> Here,wespecifiedthatthepasswordwillbehashedagainstanSHAhashalgorithm; alternatively,youcanuseanyotheralgorithmallowedbyyourJCAprovider. Note Foranexcellentintroductiontohashingalgorithms,referto http://www.unixwiz.net/techtips/iguide-crypto-hashes.html. Forthesakeofcompleteness,weincludeasmallapplicationasfollows,whichgenerates theBase64hashedpasswordthatistobeinsertedinDatabase: publicclassHash{ publicstaticvoidmain(String[]args)throwsException{ Stringpassword=args[0]; MessageDigestmd=MessageDigest.getInstance(“SHA-256”); byte[]passwordBytes=password.getBytes(); byte[]hash=md.digest(passwordBytes); StringpasswordHash= Base64.getEncoder().encodeToString(hash); System.out.println(“passwordhash:“+passwordHash); } Runningthemainprogramwithadminastheargumentwillgeneratethehash jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg=.Thishashwillbeyourupdated password,whichneedstobeupdatedinyourdatabase,asshowninthefollowing screenshot.Updatethepasswordusingthefollowingcode: UPDATEUSERSSETPASSWD=‘jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg=’ WHERELOGIN=‘admin’; YoucanupdateitwithanySQLclientofyourchoice. UsingtheDatabaseloginmoduleinyourapplication Onceyouaredonewiththeloginmoduleconfiguration,don’tforgettoreferenceit throughtheJBosswebdeployment’sdescriptor,WEB-INF/jboss-web.xml: <jboss-web> <security-domain>java:/jaas/dbdomain</security-domain> </jboss-web> SecuringEJBs Securingapplicationsbymeansofawebloginformisthemostfrequentlyusedoptionin Enterpriseapplications.Nevertheless,theHTTPprotocolisnottheonlychoiceavailable toaccessapplications.Forexample,EJBscanbeaccessedbyremoteclientsusingthe RMI-IIOPprotocol.Insuchacase,youshouldfurtherrefineyoursecuritypoliciesby restrictingaccesstotheEJBcomponents,whichareusuallyinvolvedinthebusinesslayer ofyourapplications. Tip HowdoessecurityworkattheEJBlevel? AuthenticationmustbeperformedbeforeanyEJBmethodiscalled.Authorization,onthe otherhand,occursatthebeginningofeachEJBmethodcall. OnevastareaofimprovementintroducedinJavaEE5concernstheuseofannotations, whichcanalsobeusedtoperformthebasicsecuritychecks.Therearefiveavailable annotations,whicharelistedasfollows: @org.jboss.ejb3.annotation.SecurityDomain:Thisspecifiesthesecuritydomain thatisassociatedwiththeclass/method. @javax.annotation.security.RolesAllowed:Thisspecifiesthelistofroles permittedtoaccessamethod(s)inanEJBapplication. @javax.annotation.security.RunAs:ThisassignsaroledynamicallytotheEJB applicationduringtheinvocationofthemethod.Itcanbeused,forexample,ifwe needtotemporarilyallowpermissiontoaccesscertainmethods. @javax.annotation.security.PermitAll:ThisspecifiesthatanEJBapplication canbeinvokedbyanyclient.Thepurposeofthisannotationistowidensecurity accesstosomemethodsinsituationswhereyoudon’texactlyknowwhatrolewill accesstheEJBapplication(imaginethatsomemoduleshavebeendevelopedbya thirdpartyandtheyaccessyourEJBapplicationwithsomerolesthatarenotwell identified). @javax.annotation.security.DenyAll:ThisspecifiesthatanEJBapplication cannotbeinvokedbyexternalclients.Ithasthesameconsiderationsasthosefor @PermitAll. ThefollowingsnippetisanexampleofhowtosecuretheTheatreBookerSFSB,which wediscussedinChapter4,LearningContextandDependencyInjection: @RolesAllowed(“Manager”) @SecurityDomain(“dbdomain”) @Stateful @Remote(TheatreBooker.class) publicclassTheatreBookerimplementsTheatreBooker{ } Note Becareful!ThereismorethanoneSecurityDomainAPIavailable.Youhavetoinclude org.jboss.ejb3.annotation.SecurityDomain.The@RolesAllowedannotation,onthe otherhand,needstoimportjavax.annotation.security.RolesAllowed. TheJBoss-specificannotationscanbefoundinthefollowingmavendependency: <groupId>org.jboss.ejb3</groupId> <artifactId>jboss-ejb3-ext-api</artifactId> <version>2.0.0</version> <scope>provided</scope> Annotationscanalsobeappliedatthemethodlevel;forexample,ifwewanttosecurejust thebookSeatobjectoftheTheatreBookerBeanclass,wewilltagthebookSeatmethodas follows: @RolesAllowed(“Manager”) @SecurityDomain(“dbdomain”) publicStringbookSeat(intseatId)throwsSeatBookedException{ } Whatifyoudon’twanttouseannotationstoestablishsecurityroles?Forexample,ifyou haveasecurityrolethatisusedcrosswisebyallyourEJBapplications,perhapsitis simplertouseaplainoldXMLconfigurationinsteadoftaggingallEJBswithannotations. Inthisscenario,youhavetodeclarethesecurityconstraintsfirstinthegenericMETAINF/ejb-jar.xmlfile,shownasfollows: <ejb-jarxmlns=“http://java.sun.com/xml/ns/javaee” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” version=“3.2” xsi:schemaLocation=“http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_2.xsd”> <assembly-descriptor> <method-permission> <role-name>Manager</role-name> <method> <ejb-name>*</ejb-name> <method-name>*</method-name> </method> </method-permission> </assembly-descriptor> </ejb-jar> Then,insidetheMETA-INF/jboss-ejb3.xmlconfigurationfile,justaddareferencetoyour securitydomain: <?xmlversion=“1.0”encoding=“UTF-8”?> <jboss:ejb-jarxmlns=“http://java.sun.com/xml/ns/javaee” xmlns:jboss=“http://www.jboss.com/xml/ns/javaee” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:s=“urn:security:1.1”version=“3.1”impl-version=“2.0”> <assembly-descriptor> <s:security> <ejb-name>*</ejb-name> <s:security-domain>dbdomain</s:security-domain> </s:security> </assembly-descriptor> </jboss:ejb-jar> Here’sasnapshotillustratingtheroleconfigurationoftheEJBfile: Note IfyouwanttousealoginmoduleviaEJBremoting,youmustconfigureyoursecurity realmaccordinglyusingtheJAASentry,asshowninthefollowingcode: <security-realmname=“ApplicationRealm”> <authentication> <jaasname=“dbdomain”/> </authentication> </security-realm> Additionally,youshouldplacethefollowingentriesinjbossyourjboss-ejb-clientproperties: remote.connection.default.username=admin remote.connection.default.password=admin remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEX remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOU Theseentrieswillensure(besidespassingthecredentials),thatthetransmittedpassword willnotbeadditionallyhashedbytheremotingmechanism. Securingwebservices Webserviceauthorizationcanbasicallybecarriedoutintwoways,dependingonwhether wearedealingwithaPOJO-basedwebserviceoranEJB-basedwebservice.Security changestoPOJOwebservicesareidenticaltothoseweintroducedforservlets/JSP, consistentindefiningthesecurity-constraintselementinweb.xmlandthelogin modulesinjboss-web.xml. Ifyouareusingawebclienttoaccessyourwebservice,itisallyouneedtoget authenticated.Ifyouareusingastandaloneclient,youwillneedtospecifythecredentials intheJAX-WSFactory.Thefollowingisanexampleofhowtoaccessthesecured CalculatePowerServiceinstance,whichwasdescribedinChapter7,AddingWeb ServicestoYourApplications: JaxWsProxyFactoryBeanfactory=newJaxWsProxyFactoryBean(); factory.getInInterceptors().add(newLoggingInInterceptor()); factory.getOutInterceptors().add(newLoggingOutInterceptor()); factory.setServiceClass(CalculatePowerWebService.class); factory.setAddress(“http://localhost:8080/pojoService”); factory.setUsername(“admin”); factory.setPassword(“admin”); CalculatePowerWebServiceclient=(CalculatePowerWebService) factory.create(); WhataboutEJB-basedwebservices?Theconfigurationisslightlydifferent;sincethe securitydomainisnotspecifiedinwebdescriptors,wehavetoprovideitbymeansof annotations: @Stateless @WebService(targetNamespace=“http://www.packtpub.com/”,serviceName= “TicketWebService”) @WebContext(authMethod=“BASIC”, secureWSDLAccess=false) @SecurityDomain(value=“dbdomain”) @RolesAllowed(“Manager”) publicclassTicketSOAPServiceimplementsTicketSOAPServiceItf, Serializable{ …. } Asyoucansee,[email protected] reflectsthesameconfigurationoptionsasthatofPOJO-basedwebservices,withBASIC authenticationandunrestrictedWSDLaccess. Note The@WebContextannotationcanbefoundinthefollowingdependency: <dependency> <groupId>org.jboss.ws</groupId> <artifactId>jbossws-api</artifactId> <version>1.0.2.Final</version> <scope>provided</scope> </dependency> The@org.jboss.ejb3.annotation.SecurityDomainannotationshouldbefamiliartoyou sinceweintroducedittoillustratehowtosecureanEJB.Asyoucansee,it’sa replacementfortheinformationcontainedinthejboss-web.xmlfile,exceptthatthe securitydomainisreferenceddirectlybydbdomain(insteadofjava:/jaas/dbdomain). Note TheprevioussecurityconfigurationcanalsobespecifiedbymeansoftheMETA-INF/ejbjar.xmlandMETA-INF/jboss-ejb3.xmlfileincaseyoupreferusingstandard configurationfiles. Topassyourlogincredentialstothewebservice,youcanusetheRequestContextobject: finalTicketWebServiceinfoService= service.getPort(TicketWebService.class); Map<String,Object>requestContext=((BindingProvider) infoService).getRequestContext(); requestContext.put(BindingProvider.USERNAME_PROPERTY,“admin”); requestContext.put(BindingProvider.PASSWORD_PROPERTY,“admin”); Theusernameandpasswordvalueswillbepassedtotheloginmoduledefinedinthe securitydomain,justlikeineveryotherauthenticationmethod. Securingthetransportlayer Ifyouweretocreateamission-criticalapplicationwithjustthebareconceptsyoulearned untilnow,youwouldbeexposedtoallsortsofsecuritythreats.Forexample,ifyouneed todesignapaymentgateway,wherethecreditcardinformationistransmittedbymeansof anEJBorservlet,usingjusttheauthorizationandauthenticationstackisreallynot enough,asthesensitiveinformationisstillsentacrossanetworkanditcouldbedisclosed byahacker. Inordertopreventdisclosureofcriticalinformationtounauthorizedindividualsor systems,youhavetouseaprotocolthatprovidesencryptionoftheinformation. Encryptionistheconversionofdataintoaformthatcannotbeunderstoodby unauthorizedpeople.Conversely,decryptionistheprocessofconvertingencrypteddata backintoitsoriginalformsothatitcanbeunderstood. TheprotocolsusedtosecurethecommunicationareSSLandTLS,thelatterbeing consideredareplacementfortheolderSSL. Tip Thedifferencesbetweenthetwoprotocolsareminorandverytechnical.Inshort,TLS usesstrongerencryptionalgorithmsandhastheabilitytoworkondifferentports.Forthe restofthischapter,wewillrefertoSSLforbothprotocols.CheckoutWikipediaformore informationonit:http://en.wikipedia.org/wiki/Transport_Layer_Security. Therearetwobasictechniquestoencryptinformation:symmetricencryption(alsocalled secret-keyencryption)andasymmetricencryption(alsocalledpublic-keyencryption). Symmetricencryptionistheoldestandbest-knowntechnique.Itisbasedonasecretkey, whichisappliedtothetextofamessagetochangethecontentinaparticularway.Aslong asboththesenderandrecipientknowthesecretkey,theycanencryptanddecryptall messagesthatusethiskey.Theseencryptionalgorithmstypicallyworkfastandarewell suitedtoencryptblocksofmessagesatonce. Onesignificantissuewithsymmetricalgorithmsistherequirementofasafe administrativeorganizationtodistributekeystousers.Thisgenerallyresultsinincreased overheadfromtheadministrativeaspectwhilethekeysremainvulnerabletounauthorized disclosureandpotentialabuse. Forthisreason,amission-criticalenterprisesystemusuallyreliesontheasymmetric encryptionalgorithms,whichtendtobeeasiertoemploy,manage,andareultimately moresecure. Asymmetriccryptography,alsoknownaspublic-keycryptography,isbasedonthe conceptthatthekeyusedtoencryptisnotthesameasthekeythatisusedtodecryptthe message.Inpractice,eachuserholdsacoupleofkeys:thepublickeythatisdistributedto otherpartiesandtheprivatekeythatiskeptasasecret.Eachmessageisencryptedwith therecipient’spublickeyandcanonlybedecrypted(bytherecipient)withhisprivatekey, asshowninthefollowingdiagram: Usingasymmetricencryption,youcanbesurethatyourmessagecannotbedisclosedtoa thirdparty.However,thereisstillonevulnerability. Supposeyouwanttoexchangesomevaluableinformationwithabusinesspartnerandto thatendarerequestinghispublickeybytelephoneoremail.Afraudulentuserintercepts youre-mailorsimplylistenstoyourconversationandquicklysendsyouafakemailwith hispublickey.Now,evenifyourdatatransmissionissecured,itwillbedirectedtothe wrongperson! Inordertosolvethisissue,weneedadocumenttoverifythatthepublickeybelongstoa particularindividual.Thisdocumentiscalledadigitalcertificateorpublic-key certificate.Adigitalcertificateconsistsofaformattedblockofdatathatcontainsthename ofthecertificateholder(whichmaybeeitherauserorsystemname)andtheholder’s publickey,alongwiththedigitalsignatureofaCertificationAuthority(CA)for authentication.TheCAatteststhatthesender’snameistheoneassociatedwiththepublic keyinthedocument. Publickeycertificatesarecommonlyusedtosecuretheinteractionwithwebsites.By default,thewebbrowsershipswithasetofpredefinedCAs;theyareusedtoverifythat thepubliccertificateservedtoabrowserwhenyouenterasecuresitehasactuallybeen issuedbytheownerofthewebsite.Inshort,ifyouconnectyourbrowserto https://www.abc.comandyourbrowserdoesn’tgiveanycertificatewarning,youcan safelyinteractwiththeentityinchargeofthesite,thatis,unlessthesiteoryourbrowser hasbeenhacked.However,thisisanotherstory. Note Simpleauthenticationandclientauthentication Inthepreviousexample,wedepictedasimpleauthentication,(alsocalledserver authentication).Inthisscenario,theonlypartythatneedstoproveitsidentityistheserver. SSL,however,isabletoperformmutualauthentication(alsocalledclientortwo-way authentication);heretoo,theserverrequestsaclientcertificateduringtheSSLhandshake overthenetwork. Clientauthenticationrequiresaclientcertificateinthex.509formatfromaCA.Thex.509 formatisanindustry-standardformatforSSLcertificates.Inthenextsection,wewill explorewhichtoolsareavailabletogeneratedigitalcertificates,andhowtogetyour certificatessignedbyaCA. EnablingtheSecureSocketLayeronWildFly WildFlyusestheJavaSecureSocketExtension(JSSE),whichisbundledintheJavaSE toleveragetheSSL/TLScommunication. AnEnterpriseapplicationcanbesecuredattwodifferentlocations:theHTTPlevelfor webapplications,andtheRMIlevelforapplicationsusingEJB.HTTPcommunicationis handledbythewebsubsystemwithinthestandalone.xml/domain.xmlfile.Securingthe RMItransportis,ontheotherhand,notalwaysacompellingrequirementofyour applications.Actually,inmostproductionenvironments,WildFlyisplacedbehinda firewall. Asyoucanseefromthefollowingdiagram,thisimpliesthatyourEJBsarenotdirectly exposedtountrustednetworks,whichusuallyconnectthroughthewebserverplacedina demilitarizedzone: InordertogetstartedwithWildFlyandSSL,weneedatoolthatgeneratesa public/privatekeypairintheformofanx.509certificateforusebytheSSLserver sockets.Thisiscoveredinthenextsection. Certificatemanagementtools Onetoolthatcanbeusedtosetupadigitalcertificateiskeytool,akeyandcertificate managementutilitythatshipswiththeJavaSE.Itenablesuserstoadministertheirown public/privatekeypairsandassociatedcertificatesforuseinself-authentication(wherethe userauthenticateshimselforherselftootherusersorservices)ordataintegrityand authenticationservices,usingdigitalsignatures.Italsoallowsuserstocachethepublic keys(intheformofcertificates)oftheircommunicatingpeers. Thekeytoolstoresthekeysandcertificatesinafiletermedkeystore,arepositoryof certificatesusedtoidentifyaclientorserver.Typically,akeystorecontainsaclientor server’sidentity,whichisprotectedbyapassword.Let’sseeanexampleofthekeystore generation: keytool-genkey-keystorewildfly.keystore-storepassmypassword-keypass mypassword-keyalgRSA-validity180-aliaswflyalias-dname“cn=John Smith,o=PackPub,c=GB” Thiscommandcreatesthekeystorenamedwildfly.keystoreintheworkingdirectory, andassignsitthepasswordmypassword.Itgeneratesapublic/privatekeypairforthe entitywhoseuniquenamehasthecommonnameJohnSmith,organizationPacktPub,and two-lettercountrycodeGB. Theresultofthisactionwillbeaself-signedcertificate(usingtheRSAsignature algorithm),whichincludesthepublickeyandtheuniquename.Thiscertificatewillbe validfor180days,andisassociatedwiththeprivatekeyinakeystoreentryreferredtoby thealiaswflyalias. Tip Aself-signedcertificateisacertificatethathasnotbeenverifiedbyaCAandthus,leaves youvulnerabletotheclassicman-in-the-middleattack.Aself-signedcertificateisonly suitableforin-houseuseorfortestingwhileyouwaitforyourrealcertificatetoarrive. SecuringtheHTTPcommunicationwithaself-signedcertificate Nowlet’sseehowyoucanusethiskeystorefiletosecureyourWildFlywebchannel. Openyourserverconfigurationfileandlocatethewebsubsystem. Withinthewebsubsystem,youhavetofirstchangethedefaulthttp-listenerand socket-bindingtohttps-listenerand“https”,andaddthesecurity-realmelement toit.Next,youhavetoinsertansslstanzawithinit,whichcontainsthedetailsofyour keystoreobject(inourexample,wedroppedthefilejboss.keystoreintotheserver configurationdirectory): <subsystemxmlns=“urn:jboss:domain:undertow:1.0”> <buffer-caches> <buffer-cachename=“default”buffer-size=“1024”buffersper-region=“1024”max-regions=“10”/> </buffer-caches> <servername=“default-server”> <https-listenername=“default”socket-binding=“https” security-realm=“EJBRealm”/> <hostname=“default-host”alias=“localhost”> <locationname=”/”handler=“welcome-content”/> <filter-refname=“server-header”/> <filter-refname=“x-powered-by-header”/> </host> </server> <servlet-containername=“default”default-buffercache=“default”stack-trace-on-error=“local-only”> <jsp-config/> </servlet-container> //somemorecode </subsystem> Asyoucansee,wereferencedEJBRealmintheconfiguration,butwestillneedtodefineit. Wewilldothisinthenextsections. Generatingtheserverandclientcertificates Startbygeneratingapublic/privatekeypairfortheentitywhoseuniquenamehasthe commonnameJohnSmith,organizationPacktPub,andtwo-lettercountrycodeGB. keytool-genkey-v-aliaswflyAlias-keyalgRSA-keysize1024-keystore wfly.keystore-validity180-keypassmypassword-storepassmypassword- dname“cn=JohnSmith,o=PacktPub,c=GB” Next,exporttheserver’spublickeyintoacertificatenamedsslPublicKey.certhatuses thepasswordmypassword. keytool-export-keystorejboss.keystore-aliaswflyAlias-file sslPublicKey.cer-keypassmypassword-storepassmypassword Nowthatwehavefinishedconfiguringtheserver,wewillgenerateakeypairforthe clienttoo.Wewilldothisbyusingthealiasejbclientaliasandthesamepropertiesas wedidfortheserver’skeystoreobject: keytool-genkey-v-aliasejbclientalias-keyalgRSA-keysize1024keystorejbossClient.keystore-validity180-keypassclientPasswordstorepassclientPassword-dname“cn=JohnSmith,o=PacktPub,c=GB” TheclientpublickeywillalsobeexportedtoacertificatenamedclientPublicKey.cer. keytool-export-keystorejbossClient.keystore-aliasejbclientalias-file clientPublicKey.cer-keypassclientPassword-storepassclientPassword Now,inordertocompletetheSSLhandshakesuccessfully,weneedtofirstimportthe client’spublickeyintotheserver’struststoreobject: keytool-import-v-trustcacerts-aliasejbclientalias-file clientPublicKey.cer-keystorejboss.keystore-keypassmypassword-storepass mypassword Theservercertificatealsoneedstobetrustedbytheclient.Youhavetwoavailableoptions tosolvethisissue,asfollows: Importtheservercertificateintotheclient’sJDKbundleofcertificates Createanewrepositoryofcertificatestrustedbytheclient(truststore) ImportingtheservercertificateintotheclientJDKmeansexecutingacertificateimport intotheclient’scertifiedauthorities. keytool-import-v-trustcacerts-aliaswflyAlias-filesslPublicKey.cerkeystoreC:\Java\jdk1.8.0_20\jre\lib\security\cacerts WejusthavetoreplacethepathweusedwithouractualJDKpathandusetheclient store’spasswordinordertocompletethisoperation(thedefaultvalueischangeit). Otherwise,ifyouwanttoimportthecertificateintoanewlycreatedtruststoreobject, justsubstitutethecacertsdestinationwithyourclient’struststoreobject. keytool-import-v-trustcacerts-aliaswflyAlias-filesslPublicKey.cerkeystorejbossClient.keystore-keypassclientPassword-storepass clientPassword Note Ifyouchoosethelatteroption,youneedtoaddthefollowingpropertiestoyourclient’s JDKarguments,whichwilloverridethedefaultJDK’struststoreobject: java-Djavax.net.ssl.trustStore=<truststorefile> -Djavax.net.ssl.trustStorePassword=<password> CreatinganSSL-awaresecurityrealm WithinWildFly,securityrealmsareusedtosecureaccesstothemanagementinterfaces, HTTPinterface,andremoteJNDIandEJBaccess.Withinasecurityrealm,itisalso possibletodefineanidentityfortheserver;thisidentitycanbeusedforbothinbound connectionstotheserverandoutboundconnectionsbeingestablishedbytheserver. Therefore,inordertoenableSSLcommunicationforourEJBcommunicationandHTTP, wewilldefineasecurityrealm(namedEJBRealm)thatisboundtoaserveridentity,which referencestheserver’skeystoreobject,shownasfollows: <security-realmname=“EJBRealm”> <server-identities> <ssl> <keystorepath=“jboss.keystore”relativeto=“jboss.server.config.dir”keystore-password=“mypassword”/> </ssl> </server-identities> <authentication> <jaasname=“ejb-security-domain”/> </authentication> </security-realm> BesidescontainingthelocationwhereSSLcertificatesarestored,thissecurityrealmalso containstheauthenticationpolicyusedbyyourEJBs,whichisdefinedbytheJAAS’s securitydomain,namedejb-security-domain. Thefollowingisasecuritydomaindefinition,whichisasimplefile-basedsecurity domaincontainingtheusercredentialsandrolesinthefilesejb-users.propertiesand ejb-roles.properties,respectively: <security-domainname=“ejb-security-domain”cache-type=“default”> <authentication> <login-modulecode=“Remoting”flag=“optional”> <module-optionname=“password-stacking”value=“useFirstPass”/> </login-module> <login-modulecode=“org.jboss.security.auth.spi.UsersRolesLoginModule” flag=“required”> <module-optionname=“defaultUsersProperties” value=”${jboss.server.config.dir}/ejb-users.properties”/> <module-optionname=“defaultRolesProperties” value=”${jboss.server.config.dir}/ejb-roles.properties”/> <module-optionname=“usersProperties” value=”${jboss.server.config.dir}/ejb-users.properties”/> <module-optionname=“rolesProperties” value=”${jboss.server.config.dir}/ejb-roles.properties”/> <module-optionname=“password-stacking”value=“useFirstPass”/> </login-module> </authentication> </security-domain> Asyoucanimagine,youneedtocreatethetwopropertyfiles,eachwithsomevaluesin them.Forexample,here’stheejb-user.propertiesfiletobeplacedintheserver configuration’sfolder: adminUser=admin123 Thefollowingisthecorrespondingejb-roles.propertiesfilethatgrantstherole ejbRoletotheadminUserrole: adminUser=ejbRole Thelastconfigurationeffortwouldbetospecifyitinthesecurity-realmattributeof yourremotingconnector’selement: <subsystemxmlns=“urn:jboss:domain:remoting:2.0”> <endpointworker=“default”/> <http-connectorname=“http-remoting-connector” connector-ref=“default” security-realm=“EJBRealm”/> </subsystem> Let’schecktheoutcomeofourwork.First,wewilltryouttheHTTPSconnection. YouhavetorestartWildFlytoactivatethechanges.Youshouldseethefollowinglogat thebottomofyourconsole,whichinformsyouaboutthenewHTTPSchannelrunningon port8443: [org.wildfly.extension.undertow](MSCservicethread1-9)JBAS017519: UndertowHTTPlistenerdefaultlisteningon/127.0.0.1:8443 ThefollowingscreeniswhatwillbedisplayedbytheInternetExplorer(don’ttrythisat home)browser(thesamekindoferrormessage,withadifferentformat,willbedisplayed byotherbrowserssuchasFirefoxandGoogleChrome)ifyoutrytoaccesstheTicket exampleusingthesecuredchannel(forexample,https://localhost:8443/ticketagency-cdi): Whathappened?Onceyouestablishasecureconnectionwiththewebserver,theserver certificateissenttothebrowser.Sincethecertificatehasnotbeensignedbyany recognizedCA,thebrowsersecuritysandboxwarnstheuseraboutthepotentialsecurity threat. Thisisanin-housetestsowecansafelyproceedbychoosingContinuetothiswebsite. That’sallyouneedtodoinordertoactivatetheSecureSocketLayerwithaself-signed certificate. SecuringHTTPcommunicationwithacertificatesignedbyaCA Havingyourcertificatesignedrequiresacertificate-signingrequest(CSR)tobeissued toaCA,whichwillreturnasignedcertificatetobeinstalledonyourserver.Thisimpliesa costforyourorganization,whichdependsonhowmanycertificatesyourequest,the encryptionstrength,andotherfactors. Firstly,generateaCSRusingthenewlycreatedkeystoreandkeyentry: keytool-certreq-keystorejboss.keystore-aliaswflyalias-storepass mypassword-keypassmypassword-keyalgRSA-filecertreq.csr Thiswillcreateanewcertificaterequestnamedcertreq.csr,bearingthefollowing format: –—BEGINNEWCERTIFICATEREQUEST–— …… –—ENDNEWCERTIFICATEREQUEST–— ThepreviouscertificateneedstobetransmittedtotheCA.Attheendoftheenrollment phase,theCAwillreturnasignedcertificate,whichneedstobeimportedintoyour keychain.ThefollowingcodeassumesyousavedyourCAcertificateinafilenamed signed_ca.txt: keytool-import-keystorejboss.keystore-aliastestkey1-storepass mypassword-keypassmypassword-filesigned_ca.txt Now,yourwebbrowserwillrecognizeyournewcertificateasbeingsignedbyaCA,soit won’tcomplainaboutnotbeingabletovalidatethecertificate. SecuringEJBcommunication EJBclientsinteractwiththeEnterpriseEJBtierusingtheRMI-IIOPprotocol.TheRMIIIOPprotocolhasbeendevelopedbySuntocombinetheRMIprogrammingmodelwith theIIOPunderlyingtransport. SecuringtheEJBtransportisrequiredforapplicationsthathavestrictsecurepolicies, whichcannotbecarriedoutusingcleartexttransmission.Inordertodothis,weneedto besuretocompletethefollowingsteps: 1. First,generatetheSSLcertificatesandthenstoretheclient’spublickeyinthe server’skeystoreobjectandtheserver’spublickeyontheclient’struststore; we’vealreadydonethisinordertoprepareourHTTPSconnector. 2. Next,weneedtocreateanSSL-awaresecurityrealm,whichwillbeusedbythe remotingtransport.WecanusetheonecreatedfortheHTTPScommunication. 3. Finally,weneedtoapplysomechangestoourEJBapplicationsothatitactuallyuses theSSLsecurechannel.Wewillcoverthisinthenextsubsection. ConnectingtoanSSL-awaresecurityrealm AsyousawinChapter3,IntroducingJavaEE7–EJBs,theRMI-IIOPconnection propertiesarespecifiedinthejboss-ejb-client.propertiesfile,whichneedstobe tweakedabittoenableSSLconnections: remote.connections=node1 remote.connection.node1.host=localhost remote.connection.node1.port=4447 remote.connection.node1.username=adminUser remote.connection.node1.password=admin123 remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=true remote.connection.node1.connect.options.org.xnio.Options.SSL_STARTTLS=true remote.connection.node1.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS= TheSSL_ENABLEDoption,whensettotrue,enablestheremotingconnector’sSSL communication. TheSTARTTLSoptionspecifieswhethertousetheTunneledTransportLayerSecurity (TTLS)modeatstartuporwhenneeded. TheSASL_POLICY_NOANONYMOUSoptionspecifieswhetherSimpleAuthenticationand SecurityLayer(SASL)mechanisms,whichacceptanonymouslogins,arepermitted. Finally,sinceoursecurityrealmalsoincludesanauthenticationsecuritydomain,wecan choosetorestrictaccesstosomemethodsbyspecifyinga@RolesAllowedannotation, whichrequirestheroleejbRole: @RolesAllowed(“ejbRole”) publicStringbookSeat(intseatId)throwsSeatBookedException{ …. } InordertoactivatethesecuritydomainonyourEJBs,weneedtomentionitinthe assemblydescriptorofyourjboss-ejb3.xmlfile: <jboss:ejb-jar> <assembly-descriptor> <s:security> <ejb-name>*</ejb-name> <s:security-domain>ejb-security-domain</s:security-domain> </s:security> </assembly-descriptor> </jboss:ejb-jar> Now,redeploytheTicketEJBexampleapplication,followingthedirectionscontainedin Chapter3,IntroducingJavaEE7–EJBs,andexecutetheclient. Iftheconnectionissuccessful,thenyouhaveconfiguredafullyworkingandsecured remotingconnection. Summary Westartedthischapterbydiscussingthebasicconceptsofsecurityandthedifference betweenauthenticationandauthorization. WildFlyusesthePicketBoxframeworksittingontopoftheJavaAuthenticationand AuthorizationService(JAAS),whichsecuresalltheJavaEEtechnologiesrunninginthe application.Thecoresectionofthesecuritysubsystemiscontainedinthesecurity-domain elementthatperformsalltherequiredauthorizationandauthenticationchecks. Then,wetookamuchcloserlookattheloginmodules,whichareusedtostoretheuser credentialsandtheirassociatedroles.Inparticular,youlearnedhowtoapplythefile-based UserRolesloginmoduleandtheDatabaseloginmodule.Eachloginmodulecanbeused byEnterpriseapplicationsineitheraprogrammaticordeclarativeway.While programmaticsecuritycanprovideafine-grainedsecuritymodel,youshouldconsider usingdeclarativesecurity,whichallowsacleanseparationbetweenthebusinesslayerand thesecuritypolicies. Finally,inthelastsectionofthischapter,wecoveredhowtoencryptthecommunication channelusingtheSecureSocketLayerandthecertificatesproducedbythekeytoolJava utility. Inthenextchapter,wearegoingtodiscussclustering,whichistheenvironmentwhere criticalapplicationsaredeployed. Chapter11.ClusteringWildFlyApplications Inthepreviouschapters,wewentthroughthemostinterestingaspectsofdevelopingJava Enterpriseapplications.Onceyouarereadytorolloutyourapplications,itisimportant thatyouguaranteeyourcustomersaresponsiveandfault-tolerantenvironment.This requirementcanbeachievedthroughapplicationserverclustering. WildFlyclusteringisnottheproductofasinglelibraryorspecification,butratherablend oftechnologies.Inthischapter,wewillfirstintroducesomeofthebasicsofclustered programming.Then,wewillquicklymoveontotheclusterconfigurationanditssetup, whichwillberequiredtodeploysomeclusteredapplications. Thefollowinglistisapreviewofthetopicsthatwillbecoveredinthischapter: WhatclusteringisandhowWildFlyimplementsit Settingupclustersinthestandaloneanddomainmode DevelopingclusteredJavaEE7applicationsinordertoachieveloadbalancingand highavailability Clusteringbasics Aclusterofapplicationserversconsistsofmultipleserverinstances(clusternodes) runningsimultaneouslyandworkingtogethertoprovideincreasedscalabilityand reliability.Thenodesthatmakeupaclustercanbelocatedeitheronthesamemachineor differentmachines.Fromtheclient’spointofview,thisisirrelevantbecausethecluster appearsasasingleserverinstance. Introducingclusteringinyourapplicationswillproducethefollowingbenefits: Horizontalscalability(scalingout):Addinganewnodetoaclustershouldallow theoverallsystemtoserviceahigherclientloadthanthatprovidedbyasimplebasic configuration.Ideally,itshouldbepossibletoserviceanygivenloadsimplyby addingtheappropriatenumberofserversormachines. Loadbalancing:Inaclusteredenvironment,theindividualnodesthatcomposethe clustershouldeachprocessafairshareoftheoverallclientload.Thiscanbe achievedbydistributingclientrequestsacrossmultipleservers,whichisalsoknown asloadbalancing. Highavailability:Applicationsrunninginaclustercancontinuetodosowhena serverinstancefails.Thisisachievedbecauseapplicationsaredeployedonmultiple nodesofthecluster,andsoifaserverinstancefails,anotherserverinstanceonwhich thatcomponentisdeployedcancontinuewithapplicationprocessing. WildFlyclustering ClusteringisavailableinWildFlyoutofthebox.Thereisnoall-in-onelibrarythatdeals withclustering,butratherasetoflibrariesthatcoverdifferentkindsofaspects. ThefollowingdiagramshowsthebasicclusteringarchitectureadoptedbyWildFly: ThebackboneofJBossclusteringistheJGroupslibrary,whichprovidescommunication betweenmembersoftheclusterusingamulticasttransmission. Note Multicastisaprotocolwheredataistransmittedsimultaneouslytoagroupofhoststhat havejoinedtheappropriatemulticastgroup.Youcanthinkaboutmulticastasaradioor televisionstreamingwhereonlythosetunedtoaparticularfrequencyreceivethe streaming. ThenextbuildingblockisInfinispan,whichhandlestheconsistencyofyourapplication acrosstheclusterbymeansofareplicatedandtransactionalJSR-107-compatiblecache. Note JSR-107specifiestheAPIandsemanticsfortemporaryin-memorycachingofJava objects,includingobjectcreation,sharedaccess,spooling,invalidation,andconsistency acrossJVMs. Beforedivingintosomeclusterexamples,wewillfirstneedtodescribehowtosetupa clusterofWildFlynodesusingthetwoavailablenodes:standaloneclusteranddomain cluster.Ifyoudon’trememberthedifferencebetweenthestandaloneanddomainmode orwhatcoredomainelementsare,youcanrevisethematerialfromChapter2,YourFirst JavaEEApplicationonWildFly. Startingaclusterofstandalonenodes AstandaloneserverstartsasasingleJVMprocess;therefore,weneedtostarteachserver usingthestandalone.bat/standalone.shcommand,passingalltherequiredparameters. Inthefollowingexample,wearestartingaclusteroftwoservernodesontwodifferent boxesthatareboundtotheIPaddresses192.168.1.10and192.168.1.11,respectively: ./standalone.sh-cstandalone-ha.xml-b192.168.1.10 ./standalone.sh-cstandalone-ha.xml-b192.168.1.11 The-cparameterspecifiestheserverconfigurationtobeused;outofthebox,the applicationserverincludestwostandaloneclusteringconfigurations:standalone-ha.xml andstandalone-full-ha.xml.Thelatteronealsoincludesthemessagingsubsystemand otherelementsoftheJavaEEfullprofile;therefore,ithasbeennamedthefull configuration. Theotherparameter(-b)shouldsoundfamiliartoolderJBossusers,asit’sstillusedto specifytheserver-bindingaddress,whichneedstobeuniqueinordertoavoidport conflicts. Inthisotherexample,wearestartinganotherclusteroftwonodesonthesameboxusing someadditionalparametersinordertoavoidportconflicts: ./standalone.sh-cstandalone-ha.xml-Djboss.node.name=node1 ./standalone.sh-cstandalone-ha.xml-Djboss.node.name=node2Djboss.socket.binding.port-offset=200 Asyoucansee,wehadtospecifytwoadditionalparameters:jboss.node.nameinorderto assignauniqueservernametoeachnodeandasocket-bindingport,whichusesanoffset of200.So,forexample,thesecondnodewouldrespondtotheHTTPchannelonport8280 insteadofport8080. Note Don’tbesurprisedifyoudon’tseeanymessageaboutclusteringonyourserverconsole. Clusteringmodulesareactivatedondemand,sofirstyouneedtodeployanapplication thatiscluster-aware.Inafewminutes,wewillshowyouhow. Startingaclusterofdomainnodes Inordertoconfigureaclusterrunningonadomainofservernodes,youneedtoconfigure themaindomain.xmlfileforyourdomaincontroller.Then,foreveryWildFlyhostthatis apartofthecluster,youneedtoprovideahost.xmlconfigurationfile,whichdescribes theconfigurationofasingle-serverdistribution. Thedomaincontrollerconfiguration Thedomain.xmlfileislocatedatJBOSS_HOME/domain/configuration/.Itincludesthe maindomainconfiguration,whichissharedbyallserverinstances.Inthedomain.xml file,wewilldefinetheservergroupconfigurationsspecifyingaprofilethatiscompatible withclustering.Outofthebox,aWildFlydomainshipswithfourdifferentprofiles: default:ThisprofilehasthesupportofJavaEEWebProfileandsomeextensions, suchasRESTfulwebservices,orsupportforEnterpriseJavaBeans(EJB)3remote invocations full:Thisprofilesupportsallthedefaultsubsystemscontainedinthedefaultprofile andthemessagingsubsystem ha:Thisprofilecorrespondstothedefaultprofileextendedwithclustering capabilities full-ha:Thisisthefullprofilewithclusteringcapabilities So,firstspecifyacluster-awareprofileforyourservergroupsinyourdomain.xmlfile.In ourexample,wehaveadoptedthefull-haprofileforboththeservergroupssothatyou canrunthefullJavaEEstackonallyourdomainservers: <server-groups> <server-groupname=“main-server-group”profile=“full-ha”> <jvmname=“default”> <heapsize=“64m”max-size=“512m”/> </jvm> <socket-binding-groupref=”full-ha-sockets“/> </server-group> <server-groupname=“other-server-group”profile=“full-ha”> <jvmname=“default”> <heapsize=“64m”max-size=“512m”/> </jvm> <socket-binding-groupref=“full-sockets”/> </server-group> </server-groups> Whenusingafull-haprofile,youneedtoconfigureHornetQclusteringsecurity.Youcan justdisableit,oryouneedtoadditionallysetacompletelyrandomusercredentialfora JMScluster.Findtheprofilesettingsindomain.xml,andaddthefollowingcodetothe messagingsubsystem: <subsystemxmlns=“urn:jboss:domain:messaging:2.0”> <hornetq-server> <cluster-user>randomUser</cluster-user> <cluster-password>randomPassword</cluster-password> … </hornetq-server> </subsystem> Inadditiontothedomain.xmlfile,youneedtocheckwhetheryourdomaincontroller’s host.xmlfilecontainsareferencetothelocalhost,asshowninthefollowingcode snippet: <hostname=“master”xmlns=“urn:jboss:domain:2.0”> … <domain-controller> <local/> </domain-controller> … </host> Thelocalstanzameansthatthishostcontrollerwilltaketheroleofadomaincontroller. Forallotherhostscontrollers,youmustspecifytheremotedomaincontrollerhostandits port(inthisexample,weaddedsomevariablesasplaceholders).Wewillcoverthemin thenextsection. Finally,youneedtocreateamanagementuserthatwillbeusedtoestablishaconnection betweentheslavenodesandthedomaincontroller.Forthispurpose,launchtheadduser.sh/add-user.cmdscript,whichislocatedintheJBOSS_HOME/bindirectoryofyour distribution: Whattypeofuserdoyouwishtoadd? a)ManagementUser(mgmt-users.properties) b)ApplicationUser(application-users.properties) (a):a Enterthedetailsofthenewusertoadd. Usingrealm‘ManagementRealm’asdiscoveredfromtheexistingproperty files. Username:admin1234 Passwordrecommendationsarelistedbelow.Tomodifytheserestrictions edittheadd-user.propertiesconfigurationfile. -Thepasswordshouldnotbeoneofthefollowingrestrictedvalues{root, admin,administrator} -Thepasswordshouldcontainatleast8characters,1alphabetic character(s),1digit(s),1non-alphanumericsymbol(s) -Thepasswordshouldbedifferentfromtheusername Password: Re-enterPassword: Whatgroupsdoyouwantthisusertobelongto?(Pleaseenteracomma separatedlist,orleaveblankfornone)[]: Abouttoadduser‘admin1234’forrealm‘ManagementRealm’ Isthiscorrectyes/no?yes Addeduser‘admin1234’tofile‘D:\Dev\Servers\wildfly8.1.0.Final\standalone\configuration\mgmt-users.properties’ Addeduser‘admin1234’tofile‘D:\Dev\Servers\wildfly8.1.0.Final\domain\configuration\mgmt-users.properties’ Addeduser‘admin1234’withgroupstofile‘D:\Dev\Servers\wildfly8.1.0.Final\standalone\configuration\mgmt-groups.properties’ Addeduser‘admin1234’withgroupstofile‘D:\Dev\Servers\wildfly8.1.0.Final\domain\configuration\mgmt-groups.properties’ IsthisnewusergoingtobeusedforoneASprocesstoconnecttoanother ASprocess? e.g.foraslavehostcontrollerconnectingtothemasterorforaRemoting connectionforservertoserverEJBcalls. yes/no?yes Torepresenttheuseraddthefollowingtotheserver-identitiesdefinition <secretvalue=“c2xvZHppYWsxMjM0”/> Pressanykeytocontinue… Asyoucanseefromtheprecedinglisting,youhavetocreateamanagementuserby specifyingausernameandpasswordforit.Youshouldanswerthepreviousquestionwith eitheryesorytoindicatethattheuserwillbeusedtoconnecttothedomaincontroller fromthehostcontroller.ThegeneratedsecretvalueistheBase64-encodedpasswordof thenewlycreateduser. Nowwecanstartthedomaincontrollerbyspecifyingtheaddressthatwillbeusedfor publicandmanagementinterfaces(inourexample,192.168.1.10)withthefollowing command: domain.sh–host-config=host-master.xml-b192.168.1.10Djboss.bind.address.management=192.168.1.10 Wehavesetthebindaddressofthephysicalnetworktothehostconfigurationwiththe jboss.bind.address.managementproperty.Themanagementinterfacemustbereachable forallthehostsinthedomaininordertoestablishaconnectionwiththedomain controller. Hostconfigurations Afterthedomaincontrollerisconfiguredandstarted,thenextstepistosetuptheother hoststhatwillconnecttothedomaincontroller.Oneachhost,wealsoneedaninstallation ofWildFly,wherewewillconfigurethehost.xmlfile.(Asanalternative,youcanname thehostfileasyoulikeandstartthedomainwiththe-host-configparameter,for example,./domain.sh-host-config=host-slave.xml.) Thefirstthingistochooseauniquenameforeachhostinourdomaininordertoavoid nameconflicts.Otherwise,thedefaultisthehostnameoftheserver. <hostname=“server1”xmlns=“urn:jboss:domain:2.0”> … </host> Also,youhavetochooseauniquenamefortheotherhost: <hostname=“server2”xmlns=“urn:jboss:domain:2.0”> … </host> Next,weneedtospecifythatthehostcontrollerwillconnecttoaremotedomain controller.WewillnotspecifytheactualIPaddressofthedomaincontrollerbutleaveitas apropertynamedjboss.domain.master.address. Additionally,weneedtospecifytheusernamethatwillbeusedtoconnecttothedomain controller.Solet’saddtheuseradmin1234,whichwecreatedonthedomaincontroller machine: <domain-controller> <remotehost=”${jboss.domain.master.address}” port=”${jboss.domain.master.port:9999}” username=“admin1234” security-realm=“ManagementRealm”/> </domain-controller> Finally,weneedtospecifytheBase64passwordfortheserveridentitythatweincludedin theremoteelement: <management> <security-realms> <security-realmname=“ManagementRealm”> <server-identities> <secretvalue=“QWxlc3NhbmRybzIh”/> </server-identities> <authentication> <propertiespath=“mgmt-users.properties”relativeto=“jboss.domain.config.dir”/> </authentication> </security-realm> <security-realmname=“ApplicationRealm”> <authentication> <propertiespath=“application-users.properties”relativeto=“jboss.domain.config.dir”/> </authentication> </security-realm> </security-realms> <management-interfaces> <native-interfacesecurity-realm=“ManagementRealm”> <socketinterface=“management” port=”${jboss.management.native.port:9999}”/> </native-interface> </management-interfaces> </management> Thefinalstepistoconfiguretheservernodesinsidethehost.xmlfileonboththehosts. So,onthefirsthost,wewillconfigureserver-oneandserver-twotoaddthemtomainserver-group: <servers> <servername=“server-one”group=“main-server-group”/> <servername=“server-two”group=“main-server-group”autostart=“false”> <socket-bindingsport-offset=“150”/> </server> </servers> Onthesecondhost,wewillconfigureserver-threeandserver-fourtoaddthemto other-server-group: <servers> <servername=“server-three”group=“other-server-group”/> <servername=“server-four”group=“other-server-group”>autostart=“false”> <socket-bindingsport-offset=“150”/> </server> </servers> Pleasenotethattheauto-startflagvalueindicatesthattheserverinstanceswillnotbe startedautomaticallyifthehostcontrollerisstarted. Forserver-twoandserver-four,aport-offsetvalueof150isconfiguredtoavoidport conflicts.Okay,nowwearedonewithourconfiguration.Assumingthatthefirsthosthas anIPaddressof192.168.1.10,wecanstartthefirsthostwiththefollowingcodesnippet: domain.sh\ -host-conifg=host.xml -b192.168.1.10\ -Djboss.domain.master.address=192.168.1.1\ -Djboss.bind.address.management=192.168.1.10 Thesecondhost(192.168.1.11)canbestartedwiththefollowingcodesnippet: domain.sh\ -host-conifg=host.xml -b192.168.1.11\ -Djboss.domain.master.address=192.168.1.1\ -Djboss.bind.address.management=192.168.1.11 Deployingclusteredapplications Ifyouhavetriedstartingyourstandaloneordomainsetofclusternodes,youwillbe surprisedthatthereisnoinformationatallaboutclusteringinyourserverlogging.Believe me,itisnotabugbutafeature!OneofthekeyfeaturesofWildFlyisthatonlyaminimal setofservicesisstarted;therefore,inordertoseeacluster’slivedemonstration,youneed todeployacluster-awareapplication.Inordertotriggerclusteringlibrariesinyour application,youcanfollowtwoapproaches: IfyourapplicationusesEnterpriseJavaBeans,youdon’thavetodoanythingmore. ThisareabringssomeimportantchangesinWildFly.Now,bydefault,thedataofall statefulsessionbeansisreplicatedinHAprofiles,andallstatelessbeansare clustered.Ifyourapplicationisdeployedonacontainerstartedwiththestandaloneha.xmlconfiguration,allremoteStatelessSessionBean(SLSB)supportfailover capabilitiesbydefault. Ifyourapplicationincludesawebapplicationarchive,youcanusetheportable <distributable/>elementinyourweb.xmlfile. Let’shavealookatboththeapproaches,startingfromclusteringEJBs. CreatingHAStatefulSessionBeans ClusteredStatefulSessionBeans(SFSB)havebuilt-infailovercapabilities.Thismeans thatthestateof@StatefulEJBsisreplicatedacrosstheclusternodessothatifoneofthe nodesintheclustergoesdown,someothernodewillbeabletotakeovertheinvocations addressedtoit.Itispossibletodisablethisfeatureforspecificbeansusingthe @Stateful(passivationCapable=false)annotation. ThefollowingdiagramdepictsatypicalexchangeofinformationbetweentheEJBclient applicationandtheremoteEJBcomponent: Asyoucansee,afterasuccessfullookupofanSFSBviaJavaNamingandDirectory Interface(JNDI),aproxyisreturnedtotheclientforsubsequentmethodinvocations. Note SincetheEJBisclustered,itwillreturnasessionIDandalongwithittheaffinityofthat session,thatis,thenameoftheclustertowhichthestatefulbeanbelongstoontheserver side.ThisaffinitywilllaterhelptheEJBclienttoroutetheinvocationsontheproxy appropriatelytoaspecificnodeinthecluster. Whilethissessioncreationrequestisgoingon,NodeAwillalsosendbackan asynchronousmessagethatcontainstheclustertopology.TheJBossEJBClient implementationwilltakenoteofthistopologyinformationandwilllateruseittocreate connectionstothenodeswithintheclusterandrouteinvocationstothosenodes,whenever necessary. Nowlet’sassumethatNodeAgoesdownandtheclientapplicationsubsequentlyinvokes ontheproxy.Atthisstage,theJBossEJBClientimplementationwillbeawareofthe clustertopology;therefore,itknowsthattheclusterhastwonodes:NodeAandNodeB. Nowwhentheinvocationarrives,itdetectsthatNodeAisdown,soitusesaselectorto fetchasuitablenodefromamongtheclusternodes.Thisexchangeisshowninthe followingdiagram: Ifasuitablenodeisfound,theJBossEJBClientimplementationcreatesaconnectionto thatnode(inourcaseNodeB)andcreatesanEJBreceiveroutofit.Attheendofthis process,theinvocationhasnowbeeneffectivelyfailedovertoadifferentnodewithinthe cluster. ClusteringtheTicketexample InChapter3,IntroducingJavaEE7–EJBs,wediscussedourticketsystemexample, whichwasbuiltaroundthefollowing: AstatefulEJBtoholdthesessiondata AsingletonEJBtostorethecacheofdata AstatelessEJBtoperformsomebusinessmethods Let’sseehowtoapplythenecessarychangestostartourapplicationinaclustercontext. Thestatelessandstatefulbeansarereadytobeclustered—noadditionalcodeisrequired; however,there’sapitfall.Asamatteroffact,thesingletonEJBthatisusedtoholdthe cacheofaseatwillbeinstantiatedonceineachJVMofthecluster.Thismeansthatif there’saserverfailure,thedatainthecachewillbelostandnewdata(inconsistent)will beused. Thereareseveralalternativestosetupacacheinaclusteredenvironment: UseaJBossproprietarysolutionthatdeploysaclusteredversionof SingletonService,whichexposesanHAsingletonof org.jboss.msc.service.Service(anexampleofthisapproachiscontainedinthe WildFlyquickstartdemoathttps://github.com/wildfly/quickstart/tree/master/clusterha-singleton) Moveyourcachetoapersistentstorage,whichmeansusingJPAtostoreandread datafromthecache(seeChapter5,CombiningPersistencewithCDI,whichincludes aJPA-basedexampleofourapplication) UseadistributeddatacachesuchasInfinispantostoredata,providingafailoverand dataconsistencytoyourcache Showingallthepossiblesolutionimplementationswould,however,makethissection excessivelylong;therefore,wewillillustratehowtousethelastoption,whichcan provideagoodarchitecturalpatternwiththeleastamountofeffort. Turningyourcacheintoadistributedcache InfinispanisadistributeddatagridplatformthatexposesaJSR-107-compatiblecache interfaceinwhichyoucanstoredataandenhanceitbyprovidingadditionalAPIsand features(suchastransactionalcache,dataevictionandexpiration,asynchronous operationsonthecache,andmore).Itsprimaryinterfaceisjavax.cache.Cache,whichis similartothejava.util.ConcurrentMapJavaSE,withsomemodificationsfordistributed environments.Inparticular,itaddstheabilitytoregister,deregister,andlistevent listeners.Also,itdefinesaCacheLoaderinterfacetoload/storecacheddata.Cache instancescanberetrievedusinganappropriateCacheManagerinterface,whichrepresents acollectionofcaches. Sohere’soursingletonTheatreBoxclassrewrittenusingtheInfinispanAPI: @Singleton @Startup @AccessTimeout(value=5,unit=TimeUnit.MINUTES) publicclassTheatreBox{ privatestaticfinalLoggerlogger= Logger.getLogger(TheatreBox.class); privateMap<Integer,Seat>seats; @Resource(lookup=“java:jboss/infinispan/tickets”) privateEmbeddedCacheManagercontainer; @PostConstruct publicvoidsetupTheatre(){ try{ this.cache=container.getCache(); logger.info(“GotInfinispancache”); intid=0; for(inti=0;i<5;i++){ addSeat(newSeat(++id,“Stalls”,40)); addSeat(newSeat(++id,“Circle”,20)); addSeat(newSeat(++id,“Balcony”,10)); } logger.info(“SeatMapconstructed.”); }catch(Exceptione){ logger.info(“Error!”+e.getMessage()); } } privatevoidaddSeat(Seatseat){ seats.put(seat.getId(),seat); } @Lock(READ) publicCollection<Seat>getSeats(){ returnCollections.unmodifiableCollection(seats.values()); } @Lock(READ) publicintgetSeatPrice(intseatId)throwsNoSuchSeatException{ returngetSeat(seatId).getPrice(); } @Lock(WRITE) publicvoidbuyTicket(intseatId)throwsSeatBookedException, NoSuchSeatException{ finalSeatseat=getSeat(seatId); if(seat.isBooked()){ thrownewSeatBookedException(“Seat”+seatId+”already booked!”); } addSeat(seat.getBookedSeat()); } @Lock(READ) privateSeatgetSeat(intseatId)throwsNoSuchSeatException{ finalSeatseat=cache.get(seatId); if(seat==null){ thrownewNoSuchSeatException(“Seat”+seatId+”doesnot exist!”); } returnseat; } } Thefirstthingwewanttostressonisthe@Resourceannotation,whichinjectsan EmbeddedCacheManagerinstance.WhentheWildFlydeployerencountersthisannotation, yourapplicationwillincludeadependencyontherequestedcachecontainer. Consequently,thecachecontainerwillautomaticallystartduringdeploymentandstop (includingallcaches)duringundeploymentofyourapplication. Subsequently,whentheEJBisinstantiated(seethemethodstart,whichisannotatedas @PostConstruct),org.infinispan.CacheiscreatedusingEmbeddedCacheManagerasa factory.Thiscachewillbeusedtostoreourhighlyavailablesetofdata. Theoperationsperformedagainstthedistributedcachearequiteintuitive:theputmethod isusedtostoreinstancesoftheSeatobjectinthecacheandthecorrespondingget methodisusedtoretrieveelementsfromit,justwhatyouwoulddousinganordinary hashmap.Theonlydifferenceisthatinourclusteredcache,everyentrymustbe serializable.BesuretomarkSeatasSerializableandcreateadefaultconstructorforit. Asfarasapplicationdeploymentisconcerned,youneedtostateadependencytothe InfinispanAPIexplicitly,whichisnotincludedasanimplicitdependencyinWildFly’s class-loadingpolicy.Thisismosteasilydonebyaddingthefollowinglinetoyour application’sMETA-INF/MANIFEST.MF: Dependencies:org.infinispanexport Weadditionallyneedtoaddthenewcachecontainertotheappropriateprofileinour domain.xmlfile(intheInfinispansubsystem): <cache-containername=“tickets”default-cache=“default”jndiname=“java:jboss/infinispan/tickets”module=“deployment.ticket-agencycluster.jar”> <transportlock-timeout=“60000”/> <replicated-cachename=“default”batching=“true”mode=“SYNC”> <lockingisolation=“REPEATABLE_READ”/> </replicated-cache> </cache-container> Note Inoursample,weareusingtheseats.values()calltogetalltheelementsfromour distributedmap,whichisinfactaninstanceoforg.infinispan.Cache.Thisoperationis normallydiscouragedindistributedcaches(notreplicated)andhasitsownlimitations. CheckouttheJavadocforthismethodat https://docs.jboss.org/infinispan/6.0/apidocs/org/infinispan/Cache.html#values()formore information.Thisishowever,nolongerthecaseforthenewestversionofInfinispan: http://infinispan.org/infinispan-7.0/. Codingthecluster-awareremoteclient TheremoteEJBclientwillnotneedanyparticularchangeinordertobeabletoachieve highavailability. Wewillonlyneedtoprepareajboss-ejb-client.propertiesfile,whichwillcontain thelistofserversthatwillbeinitiallycontacted(viaremoting)byourclientapplication: remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connections=node1,node2 remote.connection.node1.host=localhost remote.connection.node1.port=8080 remote.connection.node1.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS= remote.connection.node2.host=localhost remote.connection.node2.port=8280 remote.connection.node2.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS= Asyoucanseefromthisfile,weassumethatyouarerunningatwo-nodeclusteronthe localhostaddress:thefirstonerunningthedefaultportsettingsandthesecondoneusing anoffsetof200(justasshowninthesecondparagraphoftheStartingaclusterof standalonenodessection). Replacetheremote.connection.nodeX.hostvariable’svaluewiththeactualIPorhostif youarerunningyourservernodesondifferentmachinesfromyourclient. Deployingandtestinghighavailability Deployinganapplicationtoaclustercanbeachievedinseveralways;ifyouprefer automationinsteadofmanuallycopyingeacharchiveintothedeploymentsfolder,you canreusetheCLIdeploymentscriptcontainedinthepreviouschapter. Alternatively,ifyouareusingtheWildFlyMavenplugintodeploy,youcanparameterize itsconfiguration,includingthehostnameandtheportasvariables,whichwillbepassedto thecommandline: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>1.0.2.Final</version> <configuration> <filename>${project.build.finalName}.jar</filename> <hostname>${hostname}</hostname> <port>${port}</port> </configuration> </plugin> Therefore,youwillusethefollowingshelltocompilethepackageanddeploythe applicationonthefirstnode: mvninstallwildfly:deploy–Dhostname=localhost–Dport=9999 Forthesecondnode,youwillusethefollowing: mvninstallwildfly:deploy–Dhostname=localhost–Dport=10194 Note Deployingtheapplicationinthedomainnodeworksthesameasmentionedinthe precedingexample,exceptthatyouneedtoaddthedomaintagtoyourconfigurationand needtospecifyatleastoneservergroup.Visit https://docs.jboss.org/wildfly/plugins/maven/latest/examples/deployment-example.html formoreinformation. Onceyouhavedeployedboththeapplicationsonyourservernode,youshouldbeableto seetheclusterviewintheserverconsolelogsandalsoseethattheInfinispancachehas beenstartedandhasdiscoveredothernodesinthecluster.Youshouldseesomething similartothefollowingononeofthenodes: Beforeyoulaunchyourapplication,updateMaven’sexecplugininformation,which shouldnowreferenceourremoteEJBclientapplicationasshowninthehighlighted sectionofthefollowingcodesnippet: <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>${version.exec.plugin}</version> <executions> <execution> <goals> <goal>exec</goal> </goals> </execution> </executions> <configuration> <executable>java</executable> <workingDirectory>${project.build.directory}/exec-workingdirectory</workingDirectory> <arguments> <argument>-classpath</argument> <classpath> </classpath> <argument>com.packtpub.wflydevelopment.chapter11.client.TicketAgencyClient</argum </arguments> </configuration> </plugin> Youcanrunitusingthefollowingcommand: mvnexec:exec Thefirstpartoftheclientwillshowtheevidencethatwehavesuccessfullycompletedthe firsttransaction.Ontheclientconsole,youwillseethereturnvalueofthebooking transactionandtheSeatlist,asshowninthefollowingscreenshot: ThefollowingscreenshotshowstheservernodewhereourEJBclientlanded: Nowshutdowntheprecedingservernode(Ctrl+Cwouldsufficeifyouarestartingitas aforegroundprocess)andpressEnter(orReturnonaMac)ontheclientapplication. Asyoucanseefromthefollowingscreenshot,youshouldseethatthesessioncontinuesto runonthesurvivornodeandcorrectlydisplaysthesessionvalues(themoneyleft).Your clientwindowshouldalsodisplaytheupdatedcacheinformation. Webapplicationclustering Webapplicationclusteringinvolvestwoaspects:settingupanHTTPloadbalancerand tellingWildFlytomaketheapplication’susersessionsasHA.Howtodotheformer dependsonwhatloadbalanceryouwouldchoose(mod_clusterisoursuggestedchoice— itispreconfiguredandintegrateswithWildFlyoutofthebox);thelattercouldnotbe simpler—justaddthe<distributable/>tagtoyourapplication’sweb.xmlfile.Whenever anodefails,theuser’sHTTPsessionwillbehandledbyanotherone.Ifeverythinggoes well,theenduserwillnotknowthattherewasafailure—everythingwillbehandled behindthescenes. Let’sseehowtoactionboththesestepsinconcreteterms. Loadbalancingyourwebapplications YouhaveseveralchoicesavailableinordertoachieveloadbalancingofyourHTTP requests.Youcanoptforahardwareloadbalancerthatsitsinfrontofyourclusterof serversoryoucanchoosefromthemanyavailablesoftwaresolutionsforWildFly,which includethefollowing: UseApacheTomcat’smod_jkmoduletorouteyourrequeststoyournodes UseApachemod_proxythatconfiguresApachetoactasaproxyserverandforwards requeststoWildFlynodes UseWildFly’sbuilt-insolutionmod_clustertoachievedynamicloadbalancingof yourrequests Here,wewillillustratehowtogetstartedwithmod_cluster—amodulefortheApache HTTPserver.Theadvantageofusingmod_clusteragainstotheroptionscanbe summarizedinthefollowingkeypoints: Dynamicclusteringconfiguration Server-sidepluggableloadmetrics Lifecyclenotificationsoftheapplicationstatus Asamatteroffact,whenusingastandardloadbalancersuchasmod_jk,youhaveto provideastaticlistofnodesthatisusedtospreadtheload.Thisisaverylimitingfactor, especiallyifyouhavetodeliverupgradestoyourconfigurationbyaddingorremoving nodes;alternatively,yousimplyneedtoupgradesoftwareusedbysinglenodes.Besides this,usingaflatclusterconfigurationcanbetediousanditispronetoerrors,especiallyif thenumberofclusternodesishigh. Whenusingmod_cluster,youcandynamicallyaddorremovenodesfromyourcluster becauseclusternodesarediscoveredthroughanadvertisingmechanism. Inpractice,themod_clusterlibrariesontheHTTPsidesendUDPmessagesona multicastgroup,whichissubscribedbyWildFlynodes.ThisallowsWildFlynodesto automaticallydiscoverHTTPproxieswhenapplicationlifecyclenotificationsaresent. Thenextdiagramillustratesthisconceptbetter: Installingmod_cluster Themod_clustermoduleisimplementedasacoreWildFlymodule,whichisapartofthe distribution.OntheHTTPside,itisavailableasasetoflibrariesinstalledontheApache webserver. OntheWildFlyside,youcanfindthemod_clustermodule’ssubsystemalreadybundled aspartoftheclusteredconfigurationfile.Youcanlocateitineitherthestandaloneha.xmlfileorthestandalone-full-ha.xml(andofcourseinthedomain.xmlfile) configurationfile: <subsystemxmlns=“urn:jboss:domain:modcluster:1.2”> <mod-cluster-configadvertise-socket=“modcluster”connector=“ajp”> <dynamic-load-provider> <load-metrictype=“cpu”/> </dynamic-load-provider> </mod-cluster-config> </subsystem> Thesubsystemcontainsjustabare-bonesconfigurationthatreferencesitssocketbinding throughtheadvertise-socketelement: <socket-bindingname=“modcluster”port=“0”multicast-address=“224.0.1.105” multicast-port=“23364”/> OntheApachewebserverside,wehavetoinstallthecorelibrariesthatareusedto interactwithmod_cluster.Thisisaverysimpleprocedure;justpointthebrowsertothe latestmod_clusterreleaseathttp://www.jboss.org/mod_cluster/downloads.Besureto chooseaversionthatsuitsyouroperatingsystemandarchitecture(x86orx64). Oncethebinariesaredownloaded,extractthearchivetoafolder;then,navigatetothe extractedfolder.Themod_clusterbinariesessentiallyconsistofabundledApacheweb serverwithalltherequiredlibrariesinstalled.Topreconfigureyourinstallation,besureto runthe\httpd-2.2\bin\installconf.batfile. Note ItispossibletouseyourownApachewebserver2.2installation;justpickupthemodules fromthemod_clusterbundleandcopythemtothemodulesfolderofyourApacheweb server. IfyouchoosetouseyourownApachewebserveroverthebundledone,youhavetoload thefollowinglibrariesintoyourhttpd.conffile(thesamesetisusedinthebundled ApacheHTTP): LoadModuleproxy_modulemodules/mod_proxy.so LoadModuleproxy_ajp_modulemodules/mod_proxy_ajp.so LoadModuleproxy_http_modulemodules/mod_proxy_http.so LoadModuleproxy_cluster_modulemodules/mod_proxy_cluster.so LoadModulemanager_modulemodules/mod_manager.so LoadModuleslotmem_modulemodules/mod_slotmem.so LoadModuleadvertise_modulemodules/mod_advertise.so Eachofthesemodulescoversanimportantaspectofloadbalancing,listedasfollows: mod_proxy,mod_proxy_http,andmod_proxy_ajp:Thesearethecoremodulesthat forwardrequeststoclusternodesusingeithertheHTTP/HTTPSorAJPprotocol mod_manager:ThismodulereadstheinformationfromAS7andupdatestheshared memoryinformationinconjunctionwithmod_slotmem mod_proxy_cluster:Thismodulecontainsthebalancerformod_proxy mod_advertise:ThisisanadditionalmodulethatallowsHTTPtoadvertisevia multicastpackets—theIPandport—wherethemod_clustermoduleislistening Thenextpartoftheconfigurationthatweneedtoaddisthecoreloadbalancing configuration: Listen192.168.10.1:8888 <VirtualHost192.168.10.1:8888> <Location/> Orderdeny,allow Denyfromall Allowfrom192.168.10. </Location> KeepAliveTimeout60 MaxKeepAliveRequests0 ManagerBalancerNamemycluster ServerAdvertiseOn </VirtualHost> Basically,youhavetoreplacethe192.168.10.1IPaddresswiththeonethatyourApache webserverlistensforrequestsandtheportvalueof8888withtheoneyouwanttouseto communicatewithWildFly. Asitis,theApachevirtualhostallowsyoutohaveincomingrequestsfromthe subnetwork192.168.10. TheKeepAliveTimeoutdirectiveallowsyoutoreusethesameconnectionwithin60 seconds.Thenumberofrequestsperconnectionisunlimitedsincewearesetting MaxKeepAliveRequeststo0.TheManagerBalancerNamedirectiveprovidesthebalancer nameforyourcluster(defaultstomycluster). What’smostimportantforusistheServerAdvertisedirectivethatissettoOnanduses theadvertisemechanismtotellWildFlywhomitshouldsendtheclusterinformationto. Thisoptionisdisabledinthebundledserverbydefault.Besuretouncommentthe ServerAdvertisedirectiveinitshttpd.conffile. Now,restarttheApachewebserverandthesingleapplicationservernodes.Ifyouhave correctlyconfiguredthemodeclusterontheHTTPside,youwillseethateachWildFly nodewillstartreceivingUDPmulticastmessagesfrommod_cluster. Note IfyouarerunningonaWindowsmachine,besuretorunyourwebserverasan administrator. Ifeverythinggoeswell,youcanvisithttp://127.0.0.1:6666/mod_cluster_managerto seethestatusofyourloadbalancerandtheinterconnectednodes.Besuretonotuse GoogleChromeforthisbecauseitconsidersthe6666portasanunsecureone(itisanIRC portbydefault).Youshouldseethefollowinginformationonthesimplewebpage: mod_cluster/1.2.6.Final AutoRefreshshowDUMPoutputshowINFOoutput Nodemichal-pc(ajp://localhost:8009): EnableContextsDisableContextsBalancer:mycluster,LBGroup:,Flushpackets: Off,Flushwait:10000,Ping:10000000,Smax:65,Ttl:60000000,Status: OK,Elected:0,Read:0,Transferred:0,Connected:0,Load:100 Ifyoudon’thavearunningWildFlyinstancenow,besuretostartitwithoneofthe full-HAconfigurationfiles.RefreshApache’sconfigurationwebpageaftertheserveris up. Clusteringyourwebapplications Clusteringwebapplicationsrequirestheleastamountofefforttobeputinbythe developer.Aswehavejustdiscussed,allyouneedtodotoswitchonclusteringinaweb applicationistoaddthefollowingdirectivetotheweb.xmldescriptor: <web-app> <distributable/> </web-app> Onceyourapplicationshipswiththedistributablestanzainit,theclusterwillstart,and providedyouhavecorrectlydesignedyoursessionlayer,itwillbeloadbalancedandfault tolerantaswell. YoucouldcheckitoutbypointingthebrowsertoyourHTTPproxy.Forthedefaultsetup, itwouldbehttp://localhost:6666/your_web_application/. ProgrammingconsiderationstoachieveHA Inordertosupportin-memoryreplicationofHTTPsessionstates,allservletsandJSP sessiondatamustbeserializable. Note Serializationistheconversionofanobjecttoaseriesofbytessothattheobjectcanbe easilysavedtoapersistentstorageorstreamedacrossacommunicationlink.Thebyte streamcanthenbedeserialized,convertingthestreamintoareplicaoftheoriginalobject. Additionally,inanHTTPservletthatimplementsjavax.servlet.http.HttpSession, youneedtousethesetAttributemethodtochangetheattributesinasessionobject.If yousettheattributesinasessionobjectwithsetAttribute,bydefaulttheobjectandits attributesarereplicatedusingtheInfinispanAPI.Everytimeachangeismadetoan objectthatisinthesession,setAttributeshouldbecalledtoupdatethatobjectacrossthe cluster. Likewise,youneedtouseremoveAttributetoremoveanattributefromasessionobject. AchievingHAinJSFapplications Intheapplicationsincludedinthisbook,wehaveusedJSFandtheCDIAPItomanage thewebsession.Inthiscase,wetransparentlyreplicatetheotherservernodestothe beans,whicharemarkedas@SessionScoped. Note ClusteringJSF-basedapplicationsrequiresspecialattentionifyouaredealingwithboth HTTPandEJBsessionscreatedbySFSB.Intheearlierservlet-centricframeworks,the usualapproachwastostorereferencesofStatefulSessionBeansin javax.servlet.http.HttpSession.Whendealingwithhigh-levelJSFandCDIBeans,it isvitaltoprovidea@SessionScopedcontrollertoyourapplication,whichgetsinjectedin theSFSBreference;otherwise,youwillendupcreatinganewStatefulSessionBeans uponeachrequest. ThefollowingisanexampleofhowtoadaptyourTicketCDIapplication(describedin Chapter4,LearningContextandDependencyInjection)toaclusteredenvironment.At first,aswesaid,weneedtoincludethedistributablestanzainyourweb.xmlfiletotrigger clusteringmodules: <web-app> <distributable/> </web-app> Next,applythesamechangestotheTheatreBoxsingletonthatwedescribedinthe Turningyourcacheintoadistributedcachesection: @Singleton @Startup publicclassTheatreBox{ @Resource(lookup=“java:jboss/infinispan/container/cluster”) privateCacheContainercontainer; //Applythesamechangesdescribedin //“TurningyourCacheintoadistributedcachesection } Sinceourcontrollercomponentisboundtoa@SessionScopedstate,youdon’tneedto applyanychangesinordertopropagateyoursessionacrossservernodes: @Named @SessionScoped publicclassTheatreBookerimplementsSerializable{ } Finally,remembertoincludetheInfinispandependencyinyourMETA-INF/MANIFEST.MF: Dependencies:org.infinispanexport Onceyourapplicationisdeployedonboththenodesofyourcluster,youcantestitby hittingtheApachewebserver(http://localhost:6666/ticket-agency-clusterinour example)andstartbookingtickets: Sincethemod_clustersubsystemisconfiguredtousestickywebsessionsbydefault,all subsequentrequestsfromthesameclientwillberedirectedtothesameservernode. Therefore,byshuttingdownthestickyservernode,youwillgetevidencethatanew clusterviewhasbeencreatedandyoucancontinueshoppingontheotherservernode. Summary Thischapterwasallabouttheworldofclusteredapplications.Here,wetookyouthrough therobustclusteringfeaturesofWildFlyandappliedthemtosomeoftheexamples discussedinthisbook. Thenumberoftopicsrelatedtoclusteringmightbeexpandedtocoverafullbookofits own;however,wedecidedtostressonlyonsomefeatures.Inparticular,welearnedhow toclusterEJBsandachievefaulttoleranceincasethereisachangeintheservertopology. Next,wediscussedclusteringwebapplicationsandtheintegrationwithloadbalancing solutionssuchastheApachewebserverandmod_cluster. Inthenextchapter,wewillfocusonsomenewtopicsaddedtoJavaEE7relatedtolongtermtaskexecution:batchprocessingandconcurrencyutilities’usage. Chapter12.Long-termTasks’Execution Sofar,ourapplicationsfocusedoninteractionwiththeuser.Thismaybethemost importantaspectofyourfutureprojects,buttherearesomescenariosthatrequirea differentapproach.Maintenancetasks,importingbigsetsofdataortime-consuming computationsareusuallyaddressedinabatchmodeinsteadofaninteractivemanner. Often,thesekindsofjobsarenotpartofthestandardoperationsandshouldbeinvoked onlywhentheserverloadisatitslowestorperiodical. BeforeJavaEE7,therewasnostandardizedwaytoimplementbatchjobs(operationsthat donotrequireuserinteraction).ThedealchangedwithJSR352 (https://jcp.org/en/jsr/detail?id=352)andtheintroductionofthebatchframework,which usesanXMLlanguagetodefinejobs. Whenitcomestoprocessor-intensivetasks,thenaturalwayistothinkabout parallelization.ModernCPUshavemultiplecores,whichcanbeeasilyutilizedbythe JVM.TheonlyproblemisthatinJavaEE,usingconcurrencyprimitivesknownfromJava SEisdiscouraged.Theprogrammermayimpairthestabilityandavailabilityofthewhole container. Oncemore,thenewJSR236(https://jcp.org/en/jsr/detail?id=236)providesnewwaysto overcomethisarchitecturalobstacle.ThenewspecificationManagedExecutorServiceisa container-awareversionofExecutorServiceknownfromJavaSE. Inthischapter,wewillcoverthefollowingtopics: Howtocreateandexecutebatchjobs Whatarethedifferencesbetweendifferentbatchjobtypes HowtocreateourcustomworkerthreadsinsideaJavaEEcontainer Theoverviewofthebatchingframework Thebatchingframeworkdefinestheconceptofabatchjob,whichisafeatureofthe applicationthatcanbeexecutedwithoutuserinteraction.Asinglejobconsistsofoneor moresteps,whichcanbeexecutedsequentiallyorinparallel.Additionally,asequenceof stepscanbegroupedintoaflow.Thestartofaparallelexecutioniscalledaswitch.And finally,ifwewanttocontrolthesequenceofstepsusingconditionalstatements,weshould usedecisions.Thesefollowingfivenounsarethebasicbuildingblocksofabatch application.Tocomposesuchanapplication,wewilluseaspecificationlanguagewritten inanXMLfile,asshowninthefollowingcodesnippet: <jobid=“jobName”> <step>…</step> <step>…</step> <decision>…</decision> <flow>…</flow> <split>…</split> </job> Astepisthebasicunitofworkandourmainareaofinterest.Thebatchingframework definestwotypesofsteps,whichareasfollows: Chunksteps:Theseworkonchunksofdatainthreephases:reading,processing,and writing(foreachphase,aseparateclassiscreated).Thechunkscanbeconfigured withanumberofelementsthatshouldbeprocessedinonetransaction. Tasksteps:Theseexecuteaspecificblockofcodecreatedbytheprogrammer, withoutanyspecialconstraints.Theyareusedformostnon-dataprocessingerrands. Additionally,thebatchingframeworkallowslistenerstoregisterforthewholejobor specificphasesofthetasks. Nowthatwe’vecoveredthebasicvocabulary,itwillbebesttojumpstraighttocoding. Ourfirstbatchjob WildFlycomeswithanimplementationofJSR352calledJBeret (https://github.com/jberet/jsr352).Thismeansthatwecaneasilyextendourticket applicationwithbatchjobs,bysimplyimplementingtherequiredinterfaces;noadditional dependenciesarerequired.AllAPIsarealreadyinplaceinourcurrentsamples,sowe onlyneedtocreatesomeclassesandanXMLfiletospecifythejobflow. Asabaseforourdevelopmentinthischapter,itwouldbebesttousethecodefrom Chapter5,CombiningPersistencewithCDI.Thepersistencelayerwillallowustocodea sampleimportbatchingjob.Tokeepitsimple,let’sstartbydefininganartificialexternal servicethatwillprovideuswithIDsofticketsthatshouldbebooked.Wecandeployitas partofourapplicationorasaseparateWARfile.ThissampleisbasedonaREST endpoint,sobesuretoconfigureJAX-RSinyourdeployment(fordetails,checkout Chapter7,AddingWebServicestoYourApplications).Thisisshowninthefollowing codesnippet: @Singleton @Startup @ConcurrencyManagement(ConcurrencyManagementType.BEAN) @Path(“/external”) @Produces(MediaType.TEXT_PLAIN) publicclassPendingSeats{ privatefinalQueue<Integer>seats= newConcurrentLinkedQueue<>(); @PostConstruct privatevoidsetUp(){ for(inti=5;i<10;i++){ seats.add(i); } } @GET publicIntegergetNextSeat(){ returnseats.poll(); } } Asyoucanseeintheprecedingcodesnippet,oursampleisinitializedwithIDsfrom5to 9,andoneveryGETrequest,itwillprovidetheIDastheoutput.WhenallIDsare emitted,anullvaluewillbereturned.Thisendpointwillserveasamodelofareservation system.Forsimplicity,itproducesplaintextvaluesinsteadofJSON.Ofcourse,aflatfile oranyothersourceofdatacouldalsobeusedforintegration. Creatingachunk-basedbatchstep Ourintegrationscenariowillbeprettystraightforward.Weneedtoreadallofthe reservationIDsfromtheexternalsystemtogetthecorrespondingseatsfromourdatabase andwritethechangesbacktothedatabase.Itwouldalsobegreattowritealogwiththe operationsmadebytheimport.Let’sstartwiththeitemreader: packagecom.packtpub.wflydevelopment.chapter12.batching; importjava.io.Serializable; importjavax.batch.api.chunk.AbstractItemReader; importjavax.inject.Named; importjavax.ws.rs.client.Client; importjavax.ws.rs.client.ClientBuilder; importjavax.ws.rs.client.WebTarget; @Named publicclassExternalSystemReaderextendsAbstractItemReader{ privateWebTargettarget; @Override publicvoidopen(Serializablecheckpoint)throwsException{ finalClientrestclient=ClientBuilder.newClient(); this.target=restclient.target(“http://localhost:8080/ticketagency-longterm/rest/external”); } @Override publicObjectreadItem()throwsException{ returntarget.request().get(String.class); } } OurreaderextendstheAbstractItemReaderclasssothatwedon’thavetoimplementall methodsofthejavax.batch.api.chunk.ItemReaderinterface.Theonlytwomethodswe areinterestedinareopenandreadItem.ThefirstoneinitializestheRESTclient,which willgetthedatafromtheserver.Theimplementationisoptionalbecausenoteveryreader needsinitializationlogic.Notethatacheckpointparameterispassedtothemethod.Itcan beusedtorestartthebatchjobfromaspecificpoint.Wewill,however,leaveoutthis feature. ThereadItemmethodrequeststhedatafromanexternalserviceandreturnsasingleitem tothebatchframework.Anullvalueisanindicatorthatthereisnomoredata.Additional methodsoftheItemReaderinterfaceareresponsibleforcheckpointhandlingandclosing ofthereader. WhenwedefinetheXMLspecificationforthebatchjob,wemustusethenamesof managedbeanstorefertothereader,processor,orwriterwewant(justlikeinJSF). Therefore,weneedthe@Namedannotationinordertoprovideastring-basedqualifier;by default,itwillbealowercasenameoftheclassonwhichtheannotationisplaced.Forthe ExternalSystemReaderbean,wewillusetheexternalSystemReadername. Afteranitemisread,wemayprocessit.OurSeatProcessorclassgoesasthefollowing codesnippet: packagecom.packtpub.wflydevelopment.chapter12.batching; importjavax.batch.api.chunk.ItemProcessor; importjavax.inject.Inject; importjavax.inject.Named; importcom.packtpub.wflydevelopment.chapter12.control.SeatDao; importcom.packtpub.wflydevelopment.chapter12.entity.Seat; @Named publicclassSeatProcessorimplementsItemProcessor{ @Inject privateSeatDaodao; @Override publicObjectprocessItem(Objectid)throwsException{ Seatseat=dao.find(Long.parseLong((String)id)); if(seat!=null){ if(seat.getBooked()==true){ returnnull; } seat.setBooked(true); } returnseat; } } OurprocessorretrievesIDsfromthereaderandfindsthecorrespondingentryinthe database.Tofindtheentity,wereuseourSeatDaoclassknownfrompreviouschapters. BecausewehaveCDIworkingonthebatchframework,wecanjustinjectourEJB withoutcaringabouttransactionhandling. Iftheseatisfound,wecheckifit’salreadybooked.Ifyes,wecansimplyreturnanull valuetoomitthisitemfromfurtherprocessing. ThelaststepisSeatWriter.Thisisshowninthefollowingcodesnippet: packagecom.packtpub.wflydevelopment.chapter12.batching; importjavax.batch.api.chunk.AbstractItemWriter; importjavax.batch.runtime.context.JobContext; importjavax.inject.Inject; importjavax.inject.Named; importjavax.persistence.EntityManager; importjavax.persistence.PersistenceContext; @Named publicclassSeatWriterextendsAbstractItemWriter{ publicstaticfinalStringFILENAME_PARAM=“logFile”; @Inject privateJobContextjobContext; @PersistenceContext privateEntityManagerem; privateBufferedWriterwriter; @Override publicvoidopen(Serializableckpt)throwsException{ PropertiesjobProperties=jobContext.getProperties(); StringfileName=jobProperties.getProperty(FILENAME_PARAM); writer=newBufferedWriter(newFileWriter(fileName)); writer.write(“Importing…”); writer.newLine(); } @Override publicvoidwriteItems(List<Object>items)throwsException{ writer.write(“Chunksize:”+items.size()); writer.newLine(); for(Objectobj:items){ em.persist(obj); writer.write(“Persisted:”+obj); writer.newLine(); } } @Override publicvoidclose()throwsException{ writer.write(“Importfinished”); writer.newLine(); writer.close(); } } OurItemWriterclassstartsbydefininganopenmethod,whichgetsafileforwriting.The nameofthenewlycreatedlogfileistakenfromthejobproperties.Oursourceof informationaboutthecurrentbatchjobistheinjectedJobContextclass(thereisalsoa StepContextobjectthatprovidesinformationaboutaspecificstep).Itgivesusthe possibilitytogetthepropertiesdefinedforajob,itscurrentID,status,andadditional transientdata. Theheartofourwriteris,ofcourse,thewriteItemmethod.Itreceivesalistofitems (seatsinourcase)tobewrittenanditsresponsibilityistopersistthem.Thismethodcan beinvokedmultipletimesuptothemomentwhenthereisnomoredatatobewritten.You canconfigurethenumberofelementsthatwillbeprocessedineverychunk.What’smore, everychunkrunsinitsowntransaction. Finally,whenthelastchunkiswritten,theclosemethodwritesasummaryandclosesthe file. Allelementsarenowinplace,soweneedtocreateabatchjobspecification.Thefile externalSystem.xmlshouldbeplacedinthesrc/main/resources/META-INF/batchjobsdirectoryinyourproject.Thecontentsareasfollows: <jobid=”externalSystem”xmlns=“http://xmlns.jcp.org/xml/ns/javaee” version=“1.0”>[1] <properties> <propertyname=”logFile”value=“log.txt”/>[2] </properties> <stepid=“processData”> <chunkitem-count=“2”>[3] <readerref=”externalSystemReader”/>[4] <processorref=”seatProcessor”/> <writerref=”seatWriter”/> </chunk> </step> </job> Thestructureisprettystraightforward.First,wedefineajobIDmatchingthefilename [1].Next,inthepropertiessection,wesetapropertylogFilewiththelog.txtvalue[2] weuseditinourSeatWritertocreateanoutputfile[3].Then,wedefineastepwitha datachunk.Theitem-countattributedefinesthenumberofitemsweprocessinone transaction.Finally,wereferenceourreader,processor,andwriterintheirmatchingtags [4]. Now,whenourjobisdefined,itistimetostartit.Todothis,weneedtotheusethe BatchRuntime’sstaticmethod,getJobOperator.Inordertosimplifythesolution,wewill useaRESTendpoint’sGETmethodasawaytoinvokeourcode: packagecom.packtpub.wflydevelopment.chapter12.batching; importjava.util.Properties; importjavax.batch.runtime.BatchRuntime; importjavax.ejb.Stateless; importjavax.ws.rs.GET; importjavax.ws.rs.Path; @Stateless @Path(“/job”) publicclassJobStarter{ @GET publicStringstart(){ longjobId=BatchRuntime.getJobOperator() .start(“externalSystem”,newProperties()); returnLong.toString(jobId); } } TheJobOperatorstartmethodreturnsajobID,whichisarepresentationoftheongoing batchprocess.Weneedtoprovidethenameofthefiledefiningthebatchjobwithoutthe XMLextensionandasetofruntimeparameters. Note Thepropertiesprovidedduringruntimearenotthesameasweusedearlier!Thesekinds ofpropertiesarenotboundtoaspecificjob(incontrasttotheonesdefinedintheXML file),butcanbeaccessedfromthejobexecution.Thebatchingframeworkcallsthem parameters.Ifyouneedthiskindoflogicinyourapplication,youshouldjustpassthem duringajob’sstartupandusethejobexecutionIDtoaccessthem: JobOperatoroperator=BatchRuntime.getJobOperator(); Propertiesproperties=newProperties(); properties.put(“propertyName”,“propertyValue”); longjobId=operator.start(“externalSystem”,properties); JobExecutionexecution=operator.getJobExecution(jobId); PropertiesjobParameters=execution.getJobParameters(); Youcanpointyourbrowsertohttp://localhost:8080/ticket-agencylongterm/rest/jobandyourbatchjobshouldstartrunning!Besuretosetupyourseats beforerunningthejob(theconsoleisavailableathttp://localhost:8080/ticketagency-longterm/faces/views/setup.xhtml). AsampleoutputfileinyourWildFly’sbindirectorywouldlooklikethefollowing: Importing… Chunksize:2 Persisted:Seat[id=5,booked=true, seatType=com.packtpub.wflydevelopment.chapter12.entity.SeatType@a55bb6e] Persisted:Seat[id=6,booked=true, seatType=com.packtpub.wflydevelopment.chapter12.entity.SeatType@a55bb6e] Chunksize:2 Persisted:Seat[id=7,booked=true, seatType=com.packtpub.wflydevelopment.chapter12.entity.SeatType@440a007] Persisted:Seat[id=8,booked=true, seatType=com.packtpub.wflydevelopment.chapter12.entity.SeatType@440a007] Chunksize:1 Persisted:Seat[id=9,booked=true, seatType=com.packtpub.wflydevelopment.chapter12.entity.SeatType@307124b7] Importfinished Ofcourse,youcouldalsostartthebatchjobusingaJavaEEtimerafteraspecificeventin yourapplicationorevenasaneffectofanincomingJMSmessage.Youcanalsousethe retrievedjobIDstomonitorthealreadyrunningjobsorterminatethemondemand.The batchingframeworkAPIgivesyoumanypossibilitieswithouttoomanycomplicationsin theareaofjobmanagement. Creatingajob-basedbatchstep Ourchunk-basedjobwasgreattoprocessbigdatasets.However,whatifweonlywantto performaspecifictask?Besidescreatingchunks,wecanalsodefinestepsthatwillsimply callaprocessmethodofaspecificclass.Thesekindsofclassesmustimplementthe Batchletinterface(orextendtheAbstractBatchletclass). Inoursample,let’strytocontactanexternalAPItoaskaboutthecurrentBitcoin exchangerate(adecentralized,virtualcurrency).Then,wewillstorethecurrentpricesof ourticketsinasimpleflatfile.Ourbatchletwouldbeasfollows: @Named publicclassBitcoinTaskextendsAbstractBatchlet{ privatestaticfinalStringEXTERNAL_API= “https://api.bitcoinaverage.com/exchanges/USD”; publicstaticfinalStringFILENAME_PARAM=“bitcoinFile”; @Inject privateSeatTypeDaoseatTypeDao; @Inject privateJobContextjobContext; @Override publicStringprocess()throwsException{//[1] WebTargetapi=ClientBuilder.newClient().target(EXTERNAL_API); Responseresponse=api.request().get(); JsonObjectentity=response.readEntity(JsonObject.class);//[2] doubleaverageValue= entity.getJsonObject(“btce”).getJsonObject(“rates”).getJsonNumber(“bid”).doubleVa Map<SeatType,Double>pricesInBitcoins= calculeteBitcoinPrices(averageValue,seatTypeDao.findAll());//[3] writeToFile(pricesInBitcoins);//[4] return“OK”; } privateMap<SeatType,Double>calculeteBitcoinPrices(double averageValue,List<SeatType>findAll){ returnfindAll.stream().collect( Collectors.toMap(seatType->seatType,seatType-> seatType.getPrice()/averageValue)); } privatevoidwriteToFile(Map<SeatType,Double>pricesInBitcoins)throws Exception{ PropertiesjobProperties=jobContext.getProperties();//[5] StringfileName=jobProperties.getProperty(FILENAME_PARAM); try(BufferedWriterwriter=newBufferedWriter(new FileWriter(fileName))){ writer.write(pricesInBitcoins.toString()); writer.newLine(); } } } Theprocessmethod[1]isourentrypointtothebatchlet.WewillstartbymakingaREST requestagainstanexternalAPI[2]andusetheresponsetocalculateourpricesinbitcoins [3].Finally,wewilltrytowritesoastogathereddataintoafile.Asyoucansee,once more,weuseJobContexttogettheconfigurationpropertiesfromthebatchingframework (thefilenameinthiscase). Youmaywonder,whatisthepointofthereturntypeintheprocessmethod?Itsimply indicatesthestatusofthejob,ifithasbeencompletedsuccessfullyornot. That’sallwewantedtodoandweachieveditinasinglebatchstep:reading,processing, andwriting.Inthechunk-orientedapproach,wewillhavethreeseparatemechanismsfor this.Let’saddournewsteptoexternalSystem.xmlfromsrc/main/resources/METAINF/batch-jobs: <jobid=“externalSystem”xmlns=“http://xmlns.jcp.org/xml/ns/javaee” version=“1.0”> <properties> <propertyname=“logFile”value=“log.txt”/> <propertyname=“bitcoinFile”value=“bitcoins.txt”/>[1] </properties> <stepid=“processData”next=“checkBitcoins”>[2] <chunkitem-count=“2”> <readerref=“externalSystemReader”/> <processorref=“seatProcessor”/> <writerref=“seatWriter”/> </chunk> </step> <stepid=“checkBitcoins”>[3] <batchletref=“bitcoinTask”/> </step> </job> TherearethreenewthingstonoticeintheXMLfile.First,weaddedanewproperty, whichwereferencedearlierinourbatchlet[1].Next,wedefinedthatafterourchunk processingstep,wewouldliketoinvokeanotherone,checkBitcoins[2].Finally,we createdanewstepinwhichwereferencedourbatchletclass. Youcanonceagainstartyourjob,andafteritiscompleted,abitcoins.txtfileshould appearinWildFly’sbindirectory. We’vecoveredthefoundationofthebatchingframework,whichallowsyoutofulfillmost ofthefrequentrequirementsdefinedforenterpriseapplications.However,thereisalot moreinsidethespecification,suchassplits,partitions,andworkflow-relatedelements (statusesanddecisions)thatyoucanexploreifamoresophisticatedmechanismis requiredbythebusinessprocessesthatyou’reimplementing. OurnextstepistoprovidesomeparallelisminsideourJavaEEcontainerusingthenew concurrencyutilities. UsingconcurrencyutilitiesinJavaEE InJavaEE6(specificallyintheEJBcontainer),creationofnewthreadswasdiscouraged becausetheapplicationserverwouldnotbeabletocontrolthestabilityoftheplatformnor guaranteeanytransactionalfeatures.Thiscouldbeaproblemforapplicationsthatwould liketoeffectivelyuseCPUandexecutemultipletasksinparallel.Itwaspossibleto overcomethisusingJCAadapters,butadditionaleffortwasrequiredtoimplementthem. Fortunately,theJSR236introducestheManagedExecutorService(alongwiththe ManagedScheduledExecutorService),acontainer-awareversionoftheExecutorService usedinJavaSE.Thewell-knownAPIportedtoJavaEEwasmergedintheplatform, providingasmoothworkflowforconcurrentoperationsintheEJBcontainer.Thenew managedexecutorserviceshavethefollowingadvantagesoverthestandardones: Theyrelyonthethreadpoolprovidedbythecontainer.Thismeansthattheserver controlshavemanythreadsthatcanbespawnedfromalldeployedapplicationsand youcantweaktheconfigurationinordertoensurethedesiredqualityofservice. Thethreadconfigurationistotallyseparatedfromthecode,soitispossibletochange itwithoutchangingtheapplicationitself. Itispossibletopropagatethecallercontexttothecreatedthread.Forexample,itis possibletousethesecurityprincipaloftheuser’srequestthatinitiatedthenew thread. Theapplicationserverallowsmonitoringofthecurrentthreadcount. Threadsstartedbythemanagedexecutorscancreatenewtransactionsforbusiness components;theycannot,however,participateintransactionsfromother components. Themainpartsoftheconcurrencyutilitiesaredescribedinthefollowingtable: Component Description ManagedExecutorService Thisisusedtoexecutesubmittedtasksinanasynchronousmanner.ThedevelopermaysubmitaCallableorRunnablefunctionandusereturnedFuturetocheckfor theresultwhenitisavailable.Thecontainercontextwillbepropagatedbythecontainer. ThisinterfaceextendsthestandardExecutorServiceinterface. ThisissimilartoManagedExecutorService,butitisusedtoexecutetasksatspecifictimes(cyclic,scheduled,ordelayed). ManagedScheduledExecutorService TheinterfaceextendsthestandardScheduleExecutorService,butitadditionallyprovidestheTriggerfeature;thepossibilitytocreateadynamicobject,whichcan decidewhenaspecificeventshouldbefired(seejavax.enterprise.concurrent.Trigger). ContextService Thisisusedtocapturethecontextofthecontainer;itcanthenbeusedwhilesubmittingajobtotheexecutorservice. ManagedThreadFactory Thisisusedtocreatethreadsbythecontainer.Thedevelopercanprovideitsownthreadfactoryinordertofulfilspecificusecases(forinstance,settingspecificpropertieson thecreatedobjects). InstancesofthesecomponentscanbeobtainedusingtheJNDIlookuporthe@Resource injection.TheJavaEE7specificationrequiresthateverycontainerprovidesasetof defaultresourcesthatshouldbeinjectablewithoutanyadditionalconfiguration.So,in WildFly,theeasiestwaytogetyourhandsonthemwouldbetojusttypethefollowing code: @Resource privateManagedExecutorServiceexecutorService; @Resource privateManagedScheduledExecutorServicescheduledExecutorService; @Resource privateContextServicecontextService; Theaforementionedcodesnippetisshorthandforalookupofthedefaultinstances,which areasfollows: @Resource(lookup=“java:comp/DefaultManagedExecutorService”) privateManagedExecutorServiceexecutorService; Youcanalsofindanyadditionalexecutorservicesandtheconfigurationofthedefault onesinthestandalone.xmlfile(andinothervariantsoftheconfigurationfile).Apartof therelevantsubsystemispresentedasfollows: <subsystemxmlns=“urn:jboss:domain:ee:2.0”> <spec-descriptor-property-replacement>false</spec-descriptor-propertyreplacement> <concurrent> (…) <managed-executor-services> <managed-executor-servicename=“default”jndiname=“java:jboss/ee/concurrency/executor/default”context-service=“default” hung-task-threshold=“60000”core-threads=“5”max-threads=“25”keepalivetime=“5000”/> </managed-executor-services> (…) </concurrent> </subsystem> Asyoucansee,thestandalone.xmlfilecontainstheconfigurationofthedefault ManagedExecutorService.Youcanaddanewcustomconfigurationwithanothername andJNDIpath;youcanalsocreateaseparateoneforeverydeployedapplication. Note NotethatthedefaultManagedExecutorServicehastwoJNDInames:theoneinthe configurationandtheonedefinedintheJavaEEspecification (java:comp/DefaultManagedExecutorService).Youcanswitchtothedefaultexecutor service(andothercomponents)usingthedefault-bindingstaginthestandalone.xmlfile. Let’stakeacloserlookatsomeofthepropertiesoftheexecutorservice: core-threads:Thisdefineshowmanythreadsshouldbealiveinthethreadpoolall thetime(evenifthosethreadsareidleandtheserverishandlingnouserrequests). max-threads:Thisstateshowmanythreadstheservercanstart(includingthecore threads)ifnecessary,forinstance,whenunderheavyload. keepalive-time:Thisdefinesafterhowmanymillisecondsathreadcanbeidlebefore theserverkillsit(itonlyappliesiftherearemorethreadsrunningthanthecorethreadsparameterspecified).Thisconfigurationvaluedefineshowlongtheserver willkeeparoundtheadditionalthreadswhentheyarenotneededanymore. hung-task-threshold:Thisdefinesafterhowmanymillisecondstheserverwillmark athreadashung.Ifsetto0,athreadwillneverbemarkedashung(thethreadwill havenoexecutiontimelimit). Byusingtheseconfigurationpropertiesandcreatingadditionalexecutorservices,the serveradministratorcangainafinecontroloverthemaximumloadthattheservercan handleatagiventime.Besuretotakeacloserlookatthemduringanapplication’s performancetuning. Asfordevelopment,thedefaultconfigurationsuitsuswell,soit’stimetodiveintothe codewithanexampleusageoftheconcurrencyutilities! Introducingthreadstoenterprisebeans Whenwewereworkingwiththebatchingframework,wecontactedaRESTendpoint, whichwasmockinganexternalsysteminoursample.Now,wearegoingtoaddsome concurrencytoit. Anexternalsystemmayaggregatebookingrequestsfromseveralsources.Ifeveryrequest takesasubstantialamountoftime,itcouldbeagoodideatomakealltherequests simultaneously.Let’sstartwithcreatingCallable,whichwillreturnalistoftheseatIDs thatshouldbebooked.Thisisshowninthefollowingcodesnippet: packagecom.packtpub.wflydevelopment.chapter12.external; importjava.util.concurrent.Callable; importjavax.enterprise.concurrent.ManagedTask; importjavax.enterprise.concurrent.ManagedTaskListener; importjavax.enterprise.inject.Instance; publicclassGenerateSeatRequestFromArtificialimplements Callable<List<Integer>>,ManagedTask[1]{ @Inject privateLoggerlogger; @Inject privateInstance<TaskListener>taskListener;[2] @Override publicManagedTaskListenergetManagedTaskListener(){ returntaskListener.get();[3] } @Override publicMap<String,String>getExecutionProperties(){ returnnewHashMap<>();[4] } @Override publicList<Integer>call()throwsException{ logger.info(“Sleeping…”); Thread.sleep(5000);[5] logger.info(“Finishedsleeping!”); returnArrays.asList(4,5,6); } } Ourtaskimplements[1]twointerfaces:CallableandManagedTask.The ManagedExecutorServicerequiresanobjectthatfulfilsthecontractofaCallableor RunnableinterfaceknownfromJavaSE. TheManagedTaskinterfaceisoptional,butitallowsustoregisteraManagedTaskListener alongwiththetaskitselfandreturnadditionalpropertiesfromthetask.Thetasklistener hasasetoflifecyclecallbacks,whicharecalledduringthetask’sexecution.Wewilluse itinordertologadditionalinformationaboutourtask.Inordertocreateaninstanceofthe tasklistener,weusedtheInstance<T>class[2].ItisusedtocreateinstancesofCDI beansondemand.WereturnManagedTaskListenerinamethodfromtheManagedTask interface[3].Wedon’tneedanyadditionalproperties;therefore,wereturnanempty objectinthesecondmethodfromtheManagedTaskinterface[4]. Finally,weimplementthecallmethod;thethreadwillbesuspendedfor5seconds(to simulatelongwork)andreturnalistofpredefinedIDs. Ourtasklistenerissimplyabeanwithalogger,whichwillgetalltheinformationabout thetask’slifecycle.Thisisshowninthefollowingcodesnippet: publicclassTaskListenerimplementsManagedTaskListener{ @Inject privateLoggerlogger; @Override publicvoidtaskSubmitted(Future<?>future,ManagedExecutorService executor,Objecttask){ logger.info(“Submitted”+task); } @Override publicvoidtaskAborted(Future<?>future,ManagedExecutorService executor,Objecttask,Throwableexception){ logger.log(Level.WARNING,“Aborted”,exception); } @Override publicvoidtaskDone(Future<?>future,ManagedExecutorServiceexecutor, Objecttask,Throwableexception){ logger.info(“Finishedtask”+task); } @Override publicvoidtaskStarting(Future<?>future,ManagedExecutorService executor,Objecttask){ logger.info(“Starting”+task); } } Asyoucansee,mostoftheimplementedmethodsaregettingtheexecutorservice,future, andthetaskitselfasparameters.Wesimplylogthecurrentstatususinganinjectedlogger. So,we’vecreatedonetask,whichisprettystatic.Now,let’strytocreateanotherone, whichwillcontactadatabase.Asbefore,we’llneedaCallableimplementation,which returnsalistofintegers.Thisisshowninthefollowingcodesnippet: publicclassGenerateSeatRequestsFromDatabaseimplements Callable<List<Integer>>{ privatestaticfinalintSEATS_TO_RETURN=3; @Inject privateSeatDaodao;//[1] @Inject privateLoggerlogger; @Override publicList<Integer>call()throwsException{ logger.info(“Sleeping…”); Thread.sleep(5000);//[4] logger.info(“Finishedsleeping!”); List<Seat>databaseSeats=dao.findAll();//[2] List<Integer>freeSeats=databaseSeats.stream() .filter(seat->!seat.getBooked()) .limit(SEATS_TO_RETURN) .map(seat->seat.getId().intValue()) .collect(Collectors.toList());//[3] if(freeSeats.isEmpty()){ logger.info(“Noseatstobook”); }else{ logger.info(“Requestingbookingfor”+freeSeats); } returnfreeSeats; } } ThemaindifferencebetweenthistaskandthepreviousoneisthatweinjectedanEJB[1], whichwillstartanunderlyingtransaction.Inthecallmethod,adatabaserequestisissued [2].ThereturnedlistofseatsisthenfilteredandtransformedintoalistofIDs[3]. Additionally,asmentionedearlier,wewillstopthethreadfor5secondssothatwecan observetheexecutionlater[4]. We’vegotourbuildingblocksinplace.Now,itistimetocombinethemintoaworking example.WecanrevisitourPendingSeatsclassfromthebeginningofthischapter,as showninthefollowingcode: packagecom.packtpub.wflydevelopment.chapter12.external; @Singleton @Startup publicclassPendingSeats{ privatefinalQueue<Long>seats= newConcurrentLinkedQueue<>(); @Resource privateManagedExecutorServiceexecutorService;//[1] @Inject//[2] privateInstance<GenerateSeatRequestsFromDatabase>databaseCollector; @Inject privateInstance<GenerateSeatRequestFromArtificial>artificalCollector; @Inject privateLoggerlogger; @PostConstruct privatevoidsetUp(){ try{ List<Future<List<Integer>>>futures= executorService.invokeAll(Arrays.asList( databaseCollector.get(),artificalCollector.get() ));//[3] List<Integer>requestedIds=futures.stream().flatMap(future-> get(future).stream()).distinct() .collect(Collectors.toList());//[4] logger.info(requestedIds.toString()); }catch(InterruptedExceptione){ logger.log(Level.SEVERE,e.getMessage(),e); } } privateList<Integer>get(Future<List<Integer>>future){ try{ returnfuture.get(); }catch(InterruptedException|ExecutionExceptione){ logger.log(Level.SEVERE,e.getMessage(),e); returnnewArrayList<>(); } } } WestartbyobtaininganinstanceofManagedExecutorServiceusingthe@Resource annotation[1].Next,thepreviouslycreatedtasksareinjectedusingtheCDI’s Instance<T>classpattern[2].Thankstothis,thearemanagedbeansandhavetheir dependenciesinjected.Withthedependenciesinplace,weusetheinvokeAllmethod[3] ofexecutorServiceinordertostartallourtasksatonce(wecouldalsousemultiplecalls ofthesubmitmethod).Thereturnvaluesrepresentasetoffutureresults,whichcanbe usedtoretrievethecollecteddatawhenitisready. Atthispoint,ourtasksarealreadyrunningsowecansimplymakeablockinggetcallon thefutureresultsandwaitforthedata[4].Whenitisready,weremoveanyduplicates, andcollecttheresultsinasinglelistusingtheflatMapoperation.Asyouremember,our previoustwotaskswerewaiting5secondseach.Thankstothefactthattheyareexecuted simultaneously,weexpectthattheywillbothfinishafter5seconds. Becauseourbeanisasingletonwithastartupannotation,thewholeprocesswillbe invokedduringthedeploymentofourapplication.Feelfreetotryitoutnow! Ofcourse,thedatabasetaskrequiressomedataintheseatstableoritwillyieldempty results(that’snotabigissueforus).Ifyouwanttheapplicationtoautomaticallyseed somedatatothedatabase,youcancreateanothersingletonbean,forinstance: @Startup publicclassDatabaseInitializer{ @PersistenceContext privateEntityManagerem; @PostConstruct publicvoidsetup(){ SeatTypeseatType=newSeatType(); seatType.setPosition(SeatPosition.BALCONY); seatType.setDescription(“TestData”); seatType.setQuantity(10); seatType.setPrice(10); em.persist(seatType); Seatseat=newSeat(); seat.setSeatType(seatType); em.persist(seat); } } Besuretoadda@DependsOn(“DatabaseInitializer”)annotationonthePendingSeats bean,sothattheinitializerrunsbeforeourdatabasecollector. Ifeverythinggoeswell,youshouldseesomethinglikethisonyourconsole: 23:42:48,455INFO[TaskListener](ServerServiceThreadPool—54) SubmittedGenerateSeatRequestFromArtificial@4256cb0c 23:42:48,456INFO[GenerateSeatRequestsFromDatabase](EEManagedExecutorService-default-Thread-1)Sleeping…(1) 23:42:48,456INFO[TaskListener](EE-ManagedExecutorService-defaultThread-2)StartingGenerateSeatRequestFromArtificial@4256cb0c 23:42:48,456INFO[GenerateSeatRequestFromArtificial](EEManagedExecutorService-default-Thread-2)Sleeping…(2) 23:42:53,457INFO[GenerateSeatRequestsFromDatabase](EEManagedExecutorService-default-Thread-1)Finishedsleeping! 23:42:53,461INFO[GenerateSeatRequestFromArtificial](EEManagedExecutorService-default-Thread-2)Finishedsleeping! 23:42:53,461INFO[TaskListener](EE-ManagedExecutorService-defaultThread-2)FinishedtaskGenerateSeatRequestFromArtificial@4256cb0c 23:42:53,617INFO[GenerateSeatRequestsFromDatabase](EEManagedExecutorService-default-Thread-1)Requestingbookingfor[1] 23:42:53,621INFO[PendingSeats](ServerServiceThreadPool—54)[1,4, 5,6](3) Asyoucansee,bothtasksstartedatthesametime(1and2)intwoseparatethreads (noticetheEE-ManagedExecutorService-default-Thread-1and…-Thread-2entriesin thelog).Thefinalresultisyieldedafterroughly5seconds,anditcontainsdatafromboth thecollectors,andadditionally,iscollectedinthethreadthatoriginallysubmittedthetasks (ServerServiceThreadPool—54). YoucanalsousetheJavaVisualVMtooltovisualizeyourthreadsintheapplication server.ThetoolisavailableinyourJDKinstallationinthebindirectory(thejvisualvm executable).Afterrunningit,youshouldseeJBossinthelefttreeandtheThreadstab afterclickingontheJBossnode.Thisisshowninthefollowingscreenshot: IfyouswitchtotheThreadstabduringyourapplicationdeployment,youwillseea graph,asshowninthefollowingscreenshot: Thepurplecolordenotesasleepingthreadandthetwohighlightedthreadswithapurple partofthetimelineareourtasksduringexecution.Youcanuseadetailedthreadviewto additionallyexamineyourworkerthreads.Thisisshowninthefollowingscreenshot: JavaVisualVMoffersmanymorefeaturesusefulforeverydeveloper,suchasresource monitoringofthevirtualmachine,profiler,sampler,andothersthatareimplementedas dedicatedplugins.Besuretocheckthemout! Inthissection,weimplementedausecasethatwasalothardertocoverinaproper mannerinpreviousversionsofJavaEE.Wewereabletodothiswithlesscode,thanksto thehigh-levelAPIthatwasmadeavailabletothedevelopers. Summary Inthischapter,youlearnedhowtocreatebatchingapplicationsusingthenewbatching frameworkintwodifferentways.Next,wetriedsomeofthemechanismsprovidedbythe concurrencyutilities.Ourexplorationwentawayfromtheuserinteractionand concentratedontheinternalsofthemiddlewarelayer. Inthenextchapter,wewillfillthelastgapintheJavaEEdeveloper’stoolbox,whichis integrationtestingwithArquillian. Chapter13.TestingYourApplications Inpreviouschapters,wecoveredthemostimportanttechnologiesoftheJavaEEplatform. However,everyprofessionaldeveloperknowsthatsoftwaredevelopmentshouldbegin fromwritingtests.Atfirst,itdoesnotsoundeasytobeabletoverifythecorrectnessof theexecutionofEJBs,database-relatedcode,or,forexample,RESTservicesbutit appearsreallystraightforwardwhenusingtherighttools!Inthischapter,wewillpresent thefundamentaltestingframeworkusedforJavaEEapplicationstesting:theArquillian. Additionally,wewilltakealookatitsextensionsandrelatedlibraries. Inthischapter,wewillfocusonthefollowingtopics: Anintroductiontoenterprisetesting,frommockobjectstotheArquillianframework HowtointegrateanArquilliantestcaseforourticketmachineapplication HowtousetheEclipseIDEandMavenshelltorunArquilliantests ThemostimportantArquillianextensionsandhowtousethem Testtypes Thewordtestscanbeinterpretedinmultipleways.Mostoften,testsperformthe validationandverificationoftheapplicationrequirements.Testscanbeperformedon multiplelevels,coveringsinglemethodstowholebusinessfeatures.Testscanalsocover nonfunctionalaspectssuchassecurityorperformance. First,let’sintroducecategoriesofteststhatvalidatethefunctionalrequirements.Mike Cohnhasintroducedaconceptofthetestpyramid,whichisshownhere: Asyoucansee,themajorityoftestsinanapplicationareusuallyteststhatcoverunitsof code.Aunitcanbeasinglemethod,themostbasicfeature.Becauseofthisscope,these typeoftestsarecalledunittests.Theycanbedefinedastestswrittenbyaprogrammerto verifythatarelativelysmallpieceoffunctionalityisdoingwhatitisintendedtodo. Becausetheunitisrathersmall,thenumberofthesetestsincreasesrapidly,sothey becomethefundamentofapplicationtestingappearingonthelowestlevelofthepyramid. Thenexttypeoftestsconcernsbiggerareasofcode.Theycoverwholeservicesor businessfeatures.Thismeanstheycovermultipleunitsofcodeandconcerndifferent modulesandlibraries.Thenumberofsuchtestswouldbelowerthanthenumberofunit tests.Thistypeoftestisoftencalledanintegrationtest.Integrationtestsaredoneto demonstratethatdifferentpiecesofthesystemworktogether;sincetheycoverentire applications,theyrequiremuchmoreefforttobeputtogether.Forexample,theyusually requireresourcessuchasdatabaseinstancesandhardwaretobeallocatedforthem. Integrationtestsdoamoreconvincingjobofdemonstratinghowthesystemworks (especiallytononprogrammers);atleasttotheextentthattheintegrationtestenvironment resemblestheproductionenvironment. ThelasttypeoftestsareUItests,whichcanalsobecalledacceptancetests.Theirnumber isthesmallestintheproject;theyareusuallythemosttroublesometowritetosimulate theuserinteractingwiththeapplication.Theycoverwholerequirementsandfeatures. Let’sleavethetopicofnonfunctionaltests.Fornow,youhavetoonlyrememberthatthey cancovertopicsrelatedtoperformance,security,andsoon. Instrumentsusedfortesting Asyoucanimagine,eachkindoftestingusesadifferentapproachandoftenrequires differenttestinglibraries. Whenyou’rewritingunittests,youhavetojustprovidesomemethodinputparameters, andvalidateiftheiroutcomecoverstheexpectations.TodothisinJava,youprobably alreadyuseJUnit,TestNG,orSpock.Whenyou’removingfrombiggerpartsofcodeto testingwholeservices,someproblemsmayappear.It’softenhardtoseparatethecode you’dliketotest,tomakeittestablewithoutrunningalltheotherservices.Youusually createsomemockobjectsthatsimulatebehaviorofmodulesyoudon’twanttoincludein yourtest.Ifyouhaveanobjectwhosemethodsyouwanttotest,andifthesemethods dependonanotherobject,youcancreateamockofthedependencyratherthananactual instanceofthatdependency.Thisallowsyoutotestyourobjectinisolation. Asanexample,onecommonusecasemightbeindatabaseapplications,whereyouwould liketotest,forexample,theuserregistrationprocessbutyoudon’twanttorunthewhole database(whichmeansthatyouwillsetitsschema,someinitialdata,andfinallycleanits statemanuallyafterthetestiscomplete).Youcanmockjustthedatabaseinteractionand definethebehaviorofsomemethodsexecution,forexample,yourstubwillalwaysreturn fourusers,whichwillbehardcodedinyourtestcode. Thiskindofapproach,althoughveryimmediatetounderstandandputintopractice,has severallimitations.Firstly,itrelegatesyouintoanartificialenvironment,whereyouwill oftenmakeinvalidassumptionsaboutthebehaviorandstabilityofthatenvironment. Secondly,youwillendupwithahard-to-maintainmockcode,whichwillallowyourtests topassandgiveyouthewarmfeelingofhavingdoneagreatjob. Thirdly,sometimesit’sveryhardtoisolateaserviceyou’dliketotest,andcodemocking allitsinteractionscanbelargerthanthecodeofthemeaningfultests. So,evenifmockobjectsmaystillprovidesomebenefitstostartsystems,whereyoudon’t havefullimplementationsofaparticularsubsystem,itmightbegoodtostayascloseas possibletothetargetenvironmentthatthecodeissupposedtorunin.Atsomepoint,The NoMockMovement(NotOnlyMocksMovement)waslaunchedpointingoutthat mockingoftentakestoomuchtime,andmakesyoufocusonwritingmocksinsteadof writingtests. Arquilliantriestosolvetheseproblems.Itisaplatformthatsimplifiesintegrationtesting forJavamiddleware.Itdealswithalltheplumbingofcontainermanagement,deployment, andframeworkinitializationsothatyoucanfocusonthetaskofwritingyourtests—real tests.Arquillianminimizestheburdenonyou—forthedeveloper—bycoveringaspects surroundingtestexecution;someoftheseaspectsareasfollows: Managingthelifecycleofthecontainer(start/stop) Bundlingthetestclasswiththedependentclassesandresourcesintoadeployable archive Enhancingthetestclass(forexample,resolvingthe@Inject,@EJB,and@Resource injections) Deployingthearchivetotestapplications(deploy/undeploy),andcapturingresults andfailures Arquillianalsohasextensionsthatenhanceitsfeatures,forexample,allowingitto performUItestsorsomenonfunctionaltests. Inthenextsection,wewilldiscusswhichinstrumentsarerequiredtorunyourintegration testsusingArquillian. GettingstartedwithArquillian AlthoughArquilliandoesnotdependonaspecificbuildtool,itiscommonlyusedwith Maven;itoffersdependencymanagementandthussimplifiesthetaskofincludingthe ArquillianlibrariesintheapplicationsincetheyaredistributedintheCentralMaven repository. Dependingonthetypeofarchetypeyouusedforgeneration,youmighthaveadifferent folderstructureinyourproject;thisisnotanissue.Whatisreallyimportantisthatyou providethefollowingstructureunderyoursrcfolder: main/java/:PlaceallapplicationJavasourcefileshere(undertheJavapackage) main/resources/:Placeallapplicationconfigurationfileshere test/java/:PlacealltestJavasourcefileshere(undertheJavapackage) test/resources/:Placealltestconfigurationfileshere(forexample, persistence.xml) Sobynow,wewillbeworkingundertest/java,whichiswherewewillplaceourfirst Arquilliantestclass. WritinganArquilliantest IfyouhavebeenworkingwithJUnit(http://www.junit.org),youwillfindasimilar Arquilliantest,withsomeextraspiceinit. Inordertodothis,wewilluseEclipseandMaven,justaswehavedonesofar.Ifyouare abouttoaddtestclassestoyourproject,thereisobviouslynoneedtocreateanewproject forthispurpose.However,forlearningpurposes,wedeliveredthisexampleinaseparate projectsothatyoucanseeexactlywhattoaddinordertorunArquilliantests. Inordertoavoidrecreatingthewholeprojectfromscratch,youcouldsimplyclonethe ticket-agency-jpaprojectandnameitticket-agency-test,movingtherootpackage fromcom.packtpub.wflydevelopment.chapter5to com.packtpub.wflydevelopment.chapter13.Ifthisstillseemsliketoomuchwork,you couldsimplyimporttheChapter13projectfromthebooksample. Configuringthepom.xmlfile ThefirstthingthatisnecessarytoincludeinordertorunanArquilliantestisthejunit dependency,whichisrequiredtorunourunittests: <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> <version>4.11</version> </dependency> Inearlierchapters,weintroducedthetermBillofMaterials(BOM).Now,wewilluse theArquillianBOMinordertoimportversionsofallArquillian-relateddependencies: <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.arquillian</groupId> <artifactId>arquillian-bom</artifactId> <version>1.1.5.Final</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> We’reusingArquillianwithJUnit(likementionedbeforeotherpossibilitiesareTestNG, Spock,JBehave,andCucumber)soweneedtoincludetheappropriatedependency: <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <scope>test</scope> </dependency> Afterbeingdonewiththebasicdependencies,wenowhavetospecifythecontainer againstwhichthetestswillberun.Containeradaptersareavailableforthemoreimportant JavaEEApplicationServers(WildFly,Glassfish,WebLogic,andWebSphere),aswellas forsomeservletcontainerssuchasTomcatorJetty.Here,wewanttouseWildFlysowe willuseanappropriatecontaineradapter.However,wehaveafewpossiblechoices. Containeradapterscanbedividedintothreebasicgroups: Embedded:ThisisthemodeinwhichacontainerisrunonthesameJVMinstance thetestsarerunning.Often,acontainerruninthismodeisnotanoriginalone,but packedtoasingleJARlimitedversion. Managed:Inthismode,therealapplicationserverisrunonaseparateJVM.Asthe nameimplies,it’spossibletomanagethestateofthecontainer,runit,stopit,andso on.Bydefault,whenyourunthetest,theserverisstarted,testsarerunagainstit,and thenitisstopped.However,itispossibletoconfigureArquilliantoruntestsonthe alreadyrunninginstance. Remote:Inthismode,wejustconnecttosomeexistingserverinstanceandruntests againstit. Themostuniversalchoicetoruntestsisthemanagedcontainer.Testsarerunonthereal server,sameasontheproductionenvironment,andadditionally,itispossibletomanage itsstate,allowingforsomemoreadvancedtestssuchastestingfeaturesrelatedtohighavailabilityorcommunicationbetweentwoapplicationsthatrunondifferentinstances. Now,weneedtoaddtheappropriatecontaineradaptertoourpom.xmlfile.Todothis,we willcreateaMavenprofile: <profile> <id>arq-wildfly-managed</id> <dependencies> <dependency> <groupId>org.wildfly</groupId> <artifactId>wildfly-arquillian-container-managed</artifactId> <scope>test</scope> </dependency> </dependencies> </profile> Theremightbesituationsinwhichyou’dliketoruntestsagainstdifferentapplication servers.It’spossibletojustdefineafewMavenprofilesandruntestsafewtimes,each timeactivatingotherprofiles.Keepinmindthatsomeapplicationserversdon’tprovideall typesoftheadapters. Thereisonemorecontainer-relatedtopic.OurArquilliantestsuseaprotocolto communicatewiththemicrodeploymentontheapplicationserver.Ifwedon’tspecifythe protocol,thecontainerwillchoosethedefaultone.Inordertospecifyitmanually,wewill needtoaddtheorg.jboss.arquillian.protocoldependency(namedsoasit’s compatiblewithServlet3.0specifications): <dependency> <groupId>org.jboss.arquillian.protocol</groupId> <artifactId>arquillian-protocol-servlet</artifactId> <scope>test</scope> </dependency> WritingyourfirstArquilliantest Oncetheconfigurationiscomplete,wewillfinallycodeourtest.So,createaJavaclass namedTicketTestunderthepackage com.packtpub.wflydevelopment.chapter13.test.Thefirstthingthatyouwilladdto thisclassisthefollowingannotationthattellsJUnittouseArquillianasthetestcontroller: @RunWith(Arquillian.class) publicclassTicketServiceTest{ } Arquillianthenlooksforastaticmethodwiththe@Deploymentannotation;itcreatesa microdeploymentincludingallthespecifiedclassesandresources(insteadofdeploying thewholeapplication),allowingtotestonlypartofthesystem: @Deployment publicstaticArchive<?>createTestArchive(){ returnShrinkWrap.create(WebArchive.class) addPackage(SeatType.class.getPackage()) .addPackage(TicketService.class.getPackage()) .addPackage(LoggerProducer.class.getPackage()) .addAsResource(“META-INF/persistence.xml”) .addAsWebInfResource(EmptyAsset.INSTANCE,“beans.xml”); } ThefluentAPIprovidedbytheShrinkWrapproject(http://www.jboss.org/shrinkwrap) makesthistechniquepossibleusingthecreatemethod,whichacceptsthetypeof deploymentunit(WebArchive)astheargumentandalltheresourcesareincludedinthis archive.Inourcase,insteadofincludingallthesingleclasses,weusetheaddPackage utilitymethodthataddsalltheclassesthatarecontainedinaclasspackage(forexample, byaddingtheSeatType.class.getPackage()method,wewillincludealltheclassesthat areinthesamepackageastheSeatTypeclass).OurprojectusestheJPA,sowealsoadd persistenceconfiguration;here,wespecifyapathtothe.xmlfile,sowecanpoint,for example,tosomeothertestconfigurationusingsomeothernon-productiondatabase.And, ofcourse,wealsohavetoaddtheemptybeans.xmlfileinordertoenabletheCDI. Finally,weinjecttheservicewewouldliketotest(yes,it’spossibletoinjectservicesto testclasses)andaddonetestmethod: @Inject TicketServiceticketService; @Test publicvoidshouldCreateSeatType()throwsException{ //given finalSeatTypeseatType=newSeatType(); seatType.setDescription(“Balcony”); seatType.setPrice(11); seatType.setQuantity(5); //when ticketService.createSeatType(seatType); //then assertNotNull(seatType.getId()); } Here,theshouldCreateSeatTypemethodwillcreateanewSeatTypeattributeusingthe createSeatTypemethodfromtheTicketServiceclass.Notehowweinject TicketServicejustaswewouldifwewererunningthiscodeontheserverside. Ourfirsttestcaseisnowready.WewilljustneedtoaddanArquillianconfigurationfile namedarquillian.xmlinourproject,undersrc/test/resources: <?xmlversion=“1.0”encoding=“UTF-8”?> <arquillianxmlns=“http://jboss.org/schema/arquillian” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd”> <containerqualifier=“jboss-managed”default=“true”> <!—Additionalconfiguration—> </container> </arquillian> Youhavetoconfigurethecontaineradapter.Inthisexample,weassumethatyouhaveset theJBOSS_HOMEenvironmentvariabletotheWildFlymaindirectory.Inthiscase,nomore configurationsarerequired.However,ifyouwanttorunsomethingnon-standard,for example,connecttoaremotecontainerwithalteredmanagementports,thenthisfileisthe appropriateplacetomodifythis.Whenyoudon’tspecifyJBOSS_HOME,youcansetthe WildFlylocationusingpropertyasfollows: <containerqualifier=“jboss-managed”default=“true”> <configuration> <propertyname=“jbossHome”>C:\wildfly</property> </configuration> </container> However,thismethodmaybehardtomaintainwhenmorethanonepersonisworkingon theproject.Inordertoavoidproblems,youcanusethesystempropertyresolution,for instance,${jbossHome}. Ifyouconfiguretheremotecontainer,theconfigurationwouldlookjustlikethis: <containerqualifier=“jboss-remote”default=“true”> <configuration> <propertyname=“managementAddress”>localhost</property> <propertyname=“managementPort”>9999</property> </configuration> </container> RunningArquillianTicketTest It’spossibletorunArquilliantestsbothfromMavenandyourIDE.Youhavetoremember thatwedeclaredthecontaineradapterintheMavenprofile,soinordertorunthefull build,youhavetorunthefollowingcommandline: mvncleanpackage–Parquillian-wildfly-managed IfyouwanttorunthetestfromEclipse,youhavetonavigatetotheprojectpropertiesand selecttheMavenproperty.IntheActiveMavenProfilesfield,enterarquillianwildfly-managed(asshowninthefollowingscreenshot),whichwedeclaredearlierinthe pom.xmlfile: Nowallyouhavetodoisright-clickonyourTicketServiceTestclassandselectRunAs JUnitTest.TheArquillianenginewillstart,producingtheoutcomeofthetestintheJUnit view(youcanmakeitvisiblebynavigatingtoMenu|Window|ShowView|JUnit). Congratulations!TheJUnitconsoleaccountsforthefirsttestthatwasrunsuccessfully. Ifyouwanttouseonlyonecontainerinyourtest,thenagoodideawouldbetosetthe defaultMavenprofile,byaddingthefollowinglinestoitinthepom.xmlfile: <activation> <activeByDefault>true</activeByDefault> </activation> RunningArquilliantestsusingSpock ArquillianisnotlimitedtoonlyJUnit.Aswementionedearlier,therearealready containers,forexample,TestNGandSpock;let’sfocusonthesecondone. SpockisamoderntestingframeworkwritteninGroovyandusessomeoftheGroovy languagefeaturestomakeyourtestsmorereadableandeasiertowrite.Spock’sprimary goalistotesttheGroovycodebutitisperfecttowriteallkindsoftestsfortheJavacode. SpockintroducesafewadditionalsemanticswithitsDomainSpecificLanguage(DSL) inordertomaketestingevenmoreeasieranddeveloperfriendly. Let’srewriteourprevioustestexampleusingSpock: @RunWith(ArquillianSputnik.class) classTicketServiceTestextendsSpecification{ @Deployment defstaticWebArchivecreateTestArchive(){ returnShrinkWrap.create(WebArchive.class) .addPackage(SeatType.class.getPackage()) .addPackage(TicketService.class.getPackage()) .addPackage(LoggerProducer.class.getPackage()) .addAsResource(‘META-INF/persistence.xml’) .addAsWebInfResource(EmptyAsset.INSTANCE,‘beans.xml’); } @Inject TicketServiceticketService; def“shouldcreateSeatType”(){ given: defseatType=newSeatType(description:“Balcony”, price:11,quantity:6) when: ticketService.createSeatType(seatType); then: seatType.getId()!=null } } Youcannoticeafewdifferences.Firstofall,it’sreallyGroovy!Secondly,thetestusesa differentrunner,ArquillianSputnik.What’smore,youcanalreadynoticesomeSpock DSLhere,suchasthegiven,when,andthenconstructions,whichcomefrombehaviordrivendevelopment(BDD).Thegivenconstructionisexpectedtoputthesystemina specificstate,whendescribesanaction,andthencontainsassertionsthatverifythe outcomeofanactionperformed. ThisfullyworkingSpockexamplewiththecompletepom.xmlconfigurationcanbefound inthischapter’sexampleprojectnamedticket-agency-spock.Moreinformation concerningtheArquillianSpocktestrunner,itsfeatures,andusageinstructionscanbe foundonGitHubathttps://github.com/arquillian/arquillian-testrunner-spock.More informationconcerningSpockcanalsobefoundonGitHubat https://github.com/spockframework/spock. ShrinkWrapResolver InalmosteveryArquilliantest,youwillprobablyuseShrinkWraptocreatemicro deployments.Afterworkingwithitforabit,youwillprobablynoticesomeshortcomings. Youmightbewonderingwhathappenswhenyou’vegotatestthatreliesonsomeexternal library;doyouneedtoaddallpackagesfromthatlibrary?Theanswerisno.ShrinkWrap ResolveroffersintegrationwithMavenandbasicGradlesupportisalsoavailable.You canjustwriteinyourtestwhatdependencyyou’dliketoincludeinthearchiveanditwill bedeployedwiththemicrodeployment. Let’slookatthebasicexampleoftheShrinkWrapResolverMavenintegration: Maven.resolver().resolve(“G:A:V”).withTransitivity().asFile(); TheprecedinglinemeansthatwewanttoresolveanartifactwiththegivengroupID, artifactID,andversion(Mavencoordinatesincanonicalform)fromMaven’scentral repositorywithallitsdependencies,andconvertittoalistoffiles. However,withthisexample,youhavetomaintaintheartifactversionbothinthetestcode andbuildfile.Youcanimprovethis!Justimportsomedependenciesdatafromyour pom.xmlfile,sothatShrinkWrapResolverresolvesartifactsofthesameversionsthemain projectisusing: Maven.resolver().loadPomFromFile(“/path/to/pom.xml”). resolve(“G:A”).withTransitivity().asFile(); Sonow,firstofall,thepom.xmldataisloaded,includingalldependingmanagement sectionsandartifactsversions.Also,theartifactcoordinatesdonothavetoincludethe version. Thesearethemostbasicfeatures.Youcanfullyconfiguretheresolvermanually,the repositoriesyouwanttouse,Mavenprofilestobeapplied,andmuchmore.Let’snow grabanexample. Let’ssayyou’retestingyourprojectusingJUnitandsomefancyassertionlibrary.AssertJ (successorofFESTassertions)isafluentassertionslibrarythatallowsyoutowriteyour projectinamorehuman-readableform: assertThat(frodo.getName()).isEqualTo(“Frodo”); Usingsuchalibraryineverytestmeansyouhavetoincludeitineverymicrodeployment. Thereisanotherthingyouwillalwaysneed:thebeans.xmlfile.Solet’screatesome utilityclasses: publicclassArquillianWarUtils{ privatestaticfinalStringBEANS_XML=“beans.xml”; privatestaticfinalStringASSERTJ_COORDINATE= “org.assertj:assertj-core”; privatestaticFile[]ASSERTJ_ARTIFACT=Maven.resolver() .loadPomFromFile(“pom.xml”).resolve(ASSERTJ_COORDINATE) .withTransitivity().asFile(); publicstaticWebArchivegetBasicWebArchive(){ returnShrinkWrap.create(WebArchive.class) .addAsLibraries(ASSERTJ_ARTIFACT) .addAsWebInfResource(EmptyAsset.INSTANCE,BEANS_XML); } } Also,nowineachtestcase,you’dhavejusttowritethefollowingcode: @Deployment publicstaticWebArchivecreateDeployment(){ returnArquillianWarUtils.getBasicWebArchive() .addPackage(SomePackage.class.getPackage(); } Atsomepoint,youmightwanttodoonemorething;insteadofaddingallyourlibraries manually,youcanimportthemonruntimedependencies: Maven.resolver().loadPomFromFile(“pom.xml”) .importRuntimeDependencies().resolve() .withTransitivity().asFile(); Therearesomeunfortunatecasesinwhichisolationofapartoftheprojectforthemicro deploymentisnotpossible.Youjustaddmoreandmoreclassestoitandthereisnoend. Thismeansthatyourprojectmighthaveapoordesign,butlet’ssayyouwanttointroduce Arquillianinsomeexistinglegacyprojectandyouhadnoinfluenceonitsstructure.In thatcase,youmightwanttoimportnotjustsomeclassesorpackages,butthewhole projecttoyourintegrationtest.Somepeopledotricks;theyjustusethebasicShrinkWrap andimporta.jaror.warfileusingtheZipImporterShrinkWrap: ShrinkWrap .create(ZipImporter.class) .importFrom(newFile(“/target/myPackage.war”)) .as(WebArchive.class); Theproblemiswhatisreallyinthisarchive?Youprobablyimportanarchivecreated duringthepreviousbuildsinceitiscreatedafterfinishingthetests!What’smore,itcannot evenexistwhenyou’rejustworkingfromtheIDEandnotrunningthefullMavenbuild! It’stheplacewhereyoucanusetheMavenImporterclass.Refertothefollowingcode: ShrinkWrap.create(MavenImporter.class) .loadPomFromFile(“/path/to/pom.xml”) .importBuildOutput() .as(WebArchive.class); That’sit!Internally,itrunsthesimplifiedbuild,gatheringcompiledclassesandresources andpackingittothearchive.ItdoesnotruninsidethecompleteMavenbuildusingsome embeddedinstance,sincethatwouldbemuchtooslow.Youmightwanttoaddsucha methodtoyourtestutilities: publicclassArquillianWarUtils{ //alreadypresentedcode publicstaticWebArchivegetBasicWebArchive(){…} publicstaticWebArchiveimportBuildOutput(){ returnShrinkWrap.create(MavenImporter.class) .loadPomFromFile(“pom.xml”) .importBuildOutput() .as(WebArchive.class); } } ThereexistsasimilarfeaturefortheGradleprojectincludedsinceShrinkWrapResolver 2.2.0-alpha-1.However,itusestheGradleToolingAPIinternally: ShrinkWrap.create(EmbeddedGradleImporter.class) .forProjectDirectory(“/path/to/dir”) .importBuildOutput() .as(WebArchive.class); Atsomepoint,youmightbesurprisedthatthislastexampledidnotwork.Thereason mightbethatarquillian-bomdoesnotincludethisShrinkWrapResolverversion. However,itispossibletooverridetheBOMimportedversionswithanotherBOM.It’s prettyeasy;justinsertthemoreimportantBOMfirst: <dependencyManagement> <!—shrinkwrapresolversimportmustbebeforearquillianbom!—> <dependency> <groupId>org.jboss.shrinkwrap.resolver</groupId> <artifactId>shrinkwrap-resolver-bom</artifactId> <version>${version.shrinkwrap-resolver}</version> <scope>import</scope> <type>pom</type> </dependency> <dependency> <groupId>org.jboss.shrinkwrap</groupId> <artifactId>shrinkwrap-bom</artifactId> <version>${version.shrinkwrap}</version> <scope>import</scope> <type>pom</type> </dependency> </dependencyManagement> MoreinfoaboutShinkWrapResolvercanbefoundonitsGitHubrepositoryat https://github.com/shrinkwrap/resolver. ShrinkWrapDescriptors ThereisonemoreShrinkWrapfamilyproject.Alittlelesspopularandnotknownby manypeople,itiscalledShrinkWrapDescriptors.ItsgoalistoprovideafluentAPIfor thecreationofdescriptorresourcesyouusuallycreateandinsertinsideyourmicro deployments. Let’sstartwithanexample.Let’ssayyou’rewritingapersistenceframeworkextension. Whiledoingthis,youuseanincredibleamountofpersistence.xmlfilessuchasthe followingcode: <persistence> <persistence-unitname=“myapp”> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/DefaultDS</jta-data-source> <properties> <propertyname=“hibernate.dialect” value=“org.hibernate.dialect.HSQLDialect”/> <propertyname=“hibernate.hbm2ddl.auto”value=“create-drop”/> </properties> </persistence-unit> </persistence> WithShrinkWrapDescriptors,insteadofputtingallthesefilesinsrc/test/resources andthenreferencingthemfromparticulartests,youcanjustputsomecodeinthetest itself: finalPersistenceDescriptorpersistence=Descriptors .create(PersistenceDescriptor.class) .createPersistenceUnit() .name(“myapp”) .provider(“org.hibernate.ejb.HibernatePersistence”) .jtaDataSource(“java:/DefaultDS”) .getOrCreateProperties() .createProperty().name(“hibernate.dialect”) .value(“org.hibernate.dialect.HSQLDialect”).up() .createProperty().name(“hibernate.hbm2ddl.auto”) .value(“create-drop”).up() .up().up() SuchaPersistenceDescriptorclasscanbeexportedasStringorjustbeaddedtothe ShrinkWraparchive. Bydefault,theprojectcontainsdescriptorsreadyforallthemostimportant.xmlofJava EEplatform.However,italsoallowsforcodegenerationusingXSDandDTDfiles.Be cautious,it’sstillinalphastage.Itisstable,buttheAPImightalreadybechanged. Persistencetesting Realchallengesstartwhenyouhavetoincludeothersystemsinyourtestingprocess. Troublesmightbecausedevenbythenecessityoftestinginteractionswitharelational database.InChapter5,CombiningPersistencewithCDI,weintroducedtheJPA.Nowit’s timetodescribehowyoucantestyourinteractionswithit. Thereareafewissuesthathavetobeconsideredwhentestingdatabase-relatedcode: Howtoverifythatdatawasreallyinsertedtothedatabase? Howtomaintainthedatabasestatebetweentestsandhowtoautomaticallycleanit? Arquillianpersistenceextensionallowsyoutotestboththesethings.Beforerunningatest, youcanseedyourdatabasefrom.xml,.xls,.yaml,.json,orcustomSQLscripts.It’s donebyjustannotatingthetestcaseusingthe@UsingDataSet(“path-to-seeding-file”) annotation.Afterthetestexecution,youcancomparethedatabasestateagainstanother file,thistimeusingthe@ShouldMatchDataSet(“path-to-dataset”)annotation.Let’s lookatanexample: @Test @UsingDataSet(“datasets/seats.yml”) @ShouldMatchDataSet(“datasets/expected-seats.yml”) publicvoidshouldMakeACleanup()throwsException{ //given //fromannotation //when ticketService.doCleanUp(); //then //fromannotation } Theseats.ymlandexpected-seats.xmlfilesarejustsimpleYAMLsplacedin /src/test/resources/datasets.ThefirstfilecontainsSeatType: Seat_Type: -description:test position:“box” price:10 quantity:10 Thesecondfilecontains: Seat_Type: Sincewe’reexecutingacleanup.NotethatthenamesandvaluesusedherearetheSQL names,nottheJPAnames. JPAallowsyoutouseasecond-levelcacheinordertoimprovetheoperations performance.Withthis,notalloftheoperationsareinstantlyreflectedonthedatabase state.Duringthetestsrunning,youmightbeinterestedinthe@JpaCacheEviction annotation,whichmakesacachetoevictaftereverytestrun.Eachtestisalsowrappedin aseparatetransactionsothatitwon’tinfluencetheexecutionofothertests Ofcourse,therearesomedependenciesyouneedtomakethisextensionwork.Thereare exactlythreeofthemasfollows: <dependency> <groupId>org.jboss.arquillian.extension</groupId> <artifactId>arquillian-persistence-dbunit</artifactId> <version>1.0.0.Alpha7</version> <scope>test</scope> </dependency> Arquillianin1.1.4.Finalversionhasabugthatpassesallpersistencetestsevenwhenthey shouldnot.The1.1.5.Finalversionworkscorrectly. Afullyconfiguredexampleprojectforthischapterisnamedticket-agency-test-ape. TheArquillianPersistenceExtensionmanualisavailableonGitHubat https://github.com/arquillian/arquillian-extension-persistence. ArquillianWarp ThelastArquillianextensionthatwewilldiscusshereisWarp.Authorssaythatitallows youtowriteclient-sideteststhatassertserver-sidelogic.Tobemoredescriptive,itallows forexecutionofclientsiderequests,andthentoexecuteserversidetests.Thisfillsthegap betweenclient-sideandserver-sidetesting. InordertofullyunderstandtheWarp,wehavetointroducethe@RunAsClientannotation. Itcanbeplacedonatestclassortestmethodanditmentionsthattestswillbeexecutedon theclientsideandnotontheserverside.Thesecondimportantannotationis @Deployment,whichyouhavealreadymetonmethodcreatingthearchives.However,it cantakesomeparametersthatareBooleanvaluetestable.Ifatestableisfalse,itisalso executesontheclientside,notrepackingthedeploymentandsoon.However,Warp mixesthesetwomodesandrequires@Deployment(testable=true)and@RunAsClient annotations.Thetestclasshastobeannotatedadditionallywith@WarpTest: @RunWith(Arquillian.class) @WarpTest @RunAsClient publicclassBasicWarpTest{ @Deployment(testable=true) publicstaticWebArchivecreateDeployment(){ … } @Test publicvoidtest(){ //Warptest } } EveryWarptestusesthefollowingconstruction: Warp .initiate(Activity) .inspect(Inspection); Anactivityistheclientpartthatmakestherequests.Inspectionisaserver-sideassertion. It’salsopossibletofiltersomerequestsbyadditionalspecificationoftheObserver: Warp .initiate(Activity) .observer(Observer) .inspect(Inspection); AnObservercan,forexample,filterHTTPaddresses. Let’stakealookatsomethingmoreconcrete.ArquillianWarpalsohassomeextensions. Currently,allofthemareHTTPoriented;however,itispossibletoextendWarptocover non-HTTPusecases.Theextensionsaddsomespecialclassesfortesting: JSF JAX-RS SpringMVC Nowwe’regoingtolookattheJAX-RSpart.Todothis,wewillusethecodefrom Chapter7,AddingWebServicestoYourApplications.WewanttotestourRESTservice. Firstofall,weneedtoaddallthestandardArquillian-relateddependenciesandthe arquillian.xmlfile.FortheWarpitself,wewillneedthefollowingdependency: <dependency> <groupId>org.jboss.arquillian.extension</groupId> <artifactId>arquillian-warp</artifactId> <version>1.0.0.Alpha7</version> <type>pom</type> <scope>test</scope> </dependency> FortheJAX-RSextension,wewillneedthefollowingdependency: <dependency> <groupId>org.jboss.arquillian.extension</groupId> <artifactId>arquillian-rest-warp-impl-jaxrs-2.0</artifactId> <version>1.0.0.Alpha2</version> <scope>test</scope> </dependency> Additionally,wewillusetheJAX-RSclient: <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-client</artifactId> <version>3.0.9.Final</version> <scope>test</scope> </dependency> Ourtestwilllooklikethis: @RunWith(Arquillian.class) @WarpTest @RunAsClient publicclassSeatsResourceTest{ @Deployment(testable=true) publicstaticWebArchivedeployment(){ returnShrinkWrap.create(MavenImporter.class) .loadPomFromFile(“pom.xml”) .importBuildOutput() .as(WebArchive.class); } @ArquillianResource privateURLcontextPath;//[1] privateResteasyWebTargettarget; @Before publicvoidsetUp(){ finalResteasyClientclient= newResteasyClientBuilder().build(); this.target=client.target(contextPath+“rest/seat”); } @Test publicvoidtestasd(){ Warp.initiate(newActivity(){ @Override publicvoidperform(){ finalStringresponse=target .request(MediaType.APPLICATION_JSON_TYPE) .get(String.class);//[2] assertNotNull(response);//[3] } }).inspect(newInspection(){ privatestaticfinallongserialVersionUID=1L; @ArquillianResource privateRestContextrestContext; @AfterServlet publicvoidtestGetSeats(){ assertEquals(200, restContext.getHttpResponse().getStatusCode()); assertEquals(MediaType.APPLICATION_JSON, restContext.getHttpResponse().getContentType()); assertNotNull(restContext.getHttpResponse().getEntity()); //[4] } }); } } Firstofall,youcanseealltheannotationsmentionedearlier.WeusetheShrinkWrap ResolverMavenImporterclassheretogetthewholeprojectinthedeployment.The[1] objectistheinjectionoftheapplicationURL.In[2],weexecuteaclientrequesttogetthe seatsandin[3],wedosomebasicclient-sideassertion.In[4],wetesttheserverside,to checkiftheappropriateHTTPcodewasreturnedandsoon.Inmorecomplexscenarios, wecanexecutesomebeanslogictoconfirmthattheappropriatestatechangewas performedontheserverside.ThislastthingdistinguishestheArquillianWarpfrom runningtestsintheclientmode(a@RunAsClientannotation)anddoingassertionswith ResteasyWebTarget. Somemoreinformationconcerningthisextensioncanbefoundat https://github.com/arquillian/arquillian-extension-warp. WebSocketstesting WeintroducedthetopicofWebSocketsintheearlierchapters.Nowlet’sseehowwecan testthem.TodothisinplainJava,wewillneedaWebSocketclientimplementation;be suretoaddTyrustoyourpom.xmlfile: <dependency> <groupId>org.glassfish.tyrus.bundles</groupId> <artifactId>tyrus-standalone-client</artifactId> <scope>test</scope> <version>1.8.3</version> </dependency> Forthisexample,wewilluseTyrusasabasecodefromChapter8,AddingWebSockets. Ourtestrealizesasimplescenario.UsingtheRESTAPI,wereserveaseat,andasa WebSocketclient,wewaitforamessagebroadcastinginformationconcerningnew reservations.Let’slookatthecode: @RunAsClient @RunWith(Arquillian.class) publicclassTicketServiceTest{ privatestaticfinalStringWEBSOCKET_URL= “ws://localhost:8080/ticket-agency-test-websockets/tickets”; privatestaticfinalStringSEAT_RESOURCE_URL= “http://localhost:8080/ticket-agency-test-websockets/rest/seat”; @Deployment publicstaticArchive<?>createTestArchive(){//[1] return ShrinkWrap.create(MavenImporter.class).loadPomFromFile(“pom.xml”).importBuildOutp .as(WebArchive.class); } @Test publicvoidshouldReceiveMessageOnBooking()throwsException{ //given finalintseatNumber=4; finalDeque<JsonObject>messages=newConcurrentLinkedDeque<>(); //[2] finalCountDownLatchmessageLatch=newCountDownLatch(1);//[3] finalMessageHandler.Whole<String>handler=//[4] newMessageHandler.Whole<String>(){ @Override publicvoidonMessage(Stringmessage){ messages.add(Json .createReader(newStringReader(message)) .readObject()); messageLatch.countDown(); } }; ContainerProvider.getWebSocketContainer()//[5] .connectToServer(newEndpoint(){ @Override publicvoidonOpen(Sessionsession, EndpointConfigendpointConfig){ session.addMessageHandler(handler); } },newURI(WEBSOCKET_URL)); //when RestAssured.when() .post(SEAT_RESOURCE_URL+“/”+seatNumber) .then().statusCode(200);//[6] messageLatch.await(10,TimeUnit.SECONDS);//[7] //then[8] assertThat(messages.size(),equalTo(1)); finalJsonObjectmessage=messages.poll(); assertThat(message.getInt(“id”),equalTo(seatNumber)); } } Thetestisrunasdescribedinthischapter’sclientmodeandusesTyrus:theWebSocket clientreferenceimplementationunderthehood.Theperfectdeploymentforthistestisour wholeapplication,sowearegoingtouseMavenImporter[1].Inthetest,wedeclareda concurrentdequetogatherareceivedmessaged[2]andalatch[3],whichwewilluseto waitin[7].InordertohandleWebSocketsontheclientside,wehavetodeclareahandler [4],whichspecifiesthebehavioronreceivingthemessage.Here,wejustaddamessage toourdequeandperformalatchcountdown.In[5],wehavetoregisterthehandlerso thatitwillbeusedforanopensession.TheRESTcallisexecutedusingarest-assured library,whichprovidesafluentAPItotestRESTAPIs.Finally,in[8],weperformsome basicassertionsconcerningthereceivedmessages. Thefullyconfiguredpom.xmlfileandawholeworkingprojectcanbefoundunder ticket-agency-test-websockets. EnhancingyourArquilliantest Youmighthavenoticedthatwe,onpurpose,createdjustapartoftheintegrationtestswe needed.Wedidnotreachthelastmile,thatis,creatingseatsandreservingone.Asa matteroffact,ifyouremember,ourticketapplicationusesConversationScopetotrack theuser’snavigation.Thus,weneedtobindConversationScopeintoourtestaswell. Luckily,theWeldcontainerprovidesallthatyouneedwith org.jboss.weld.context.bound.BoundConversationContext,whichneedstobe injectedintoyourtestclass: @InjectBoundConversationContextconversationContext; @Before publicvoidinit(){ conversationContext.associate( newMutableBoundRequest(newHashMap<String,Object>(), newHashMap<String,Object>())); conversationContext.activate(); } Note Notethatthe@Beforeannotationisinvokedbeforeeachtestmethodandafterinjections haveoccurred.Inourcase,itisusedtoassociateconversationContextwith MutableBoundRequestbeforebeingactivatedbyconversationContext.activate.This isneededtomimictheconversationbehaviorfromwithintheArquilliantestbed. Justforcompleteness,youmustbeawarethatBoundRequestinterfacesaredefinedinthe WeldAPItoholdaconversationthatspansmultiplerequests,butareshorterthana session. Sohere’sthefullTicketTestclass,whichcontainsatheatrecreationandbookingseat reservationinthetestTicketAgencymethod: @RunWith(Arquillian.class) publicclassTicketTest{ @InjectBoundConversationContextconversationContext; @Before publicvoidinit(){ conversationContext.associate( newMutableBoundRequest(newHashMap<String,Object>(), newHashMap<String,Object>())); conversationContext.activate(); } @Deployment publicstaticArchive<?>createTestArchive(){ returnShrinkWrap.create(WebArchive.class,“ticket.war”) .addPackage(SeatProducer.class.getPackage()) .addPackage(Seat.class.getPackage()) .addPackage(TicketService.class.getPackage()) .addPackage(DataManager.class.getPackage()) .addAsResource(“META-INF/persistence.xml”) .addAsWebInfResource(EmptyAsset.INSTANCE,“beans.xml”); } @Inject TicketServiceticketService; @Inject BookerServicebookerService; @Inject Loggerlog; @Test publicvoidtestTicketAgency()throwsException{ SeatTypeseatType=newSeatType(); seatType.setDescription(“Balcony”); seatType.setPrice(20); seatType.setQuantity(5); ticketService.createSeatType(seatType); log.info(“CreatedSeatType”); assertNotNull(seatType.getId()); List<SeatType>listSeats=newArrayList(); listSeats.add(seatType); ticketService.createTheatre(listSeats); log.info(“CreatedTheatre”); log.info(seatType.getDescription()+”waspersistedwithid”+ seatType.getId()); bookerService.bookSeat(newLong(seatType.getId()), seatType.getPrice()); log.info(“CreatedTheatre”); log.info(“Moneyleft:”+bookerService.getMoney()); assertTrue(bookerService.getMoney()<100); } } Additionalinformation TheArquillianprojectisanevolvingframeworkwithmanyotherinterestingtopics. Describingallitsextensions,however,isoutofthescopeofthisbook.However,theother interestingareastolookintoareDroneandGraphene,whichbringtheWebDriverand PageObjectpatternstoArquilliantesting. Atsomepoint,youmayfindyourselfcreatingseparatedeploymentmethodsineachtest case.YoucanchangethisbehaviorbytheusageofArquillianSuiteExtension,which allowsspecifyingadeploymentforasetoftestcases. Arquillianisfullyopensource,soyoucanlearnmoreaboutitfromtheonline documentationthatisavailableathttp://arquillian.org/.Whenyouneedsomehelp,oryou haveanawesomeideaforanewfeature,youcancontacttheArquilliancommunityon forumsorIRC(http://arquillian.org/community/).Rememberthatifyoufindabug,don’t complain;justfileanissueonJBossJIRAathttps://issues.jboss.org. OneoftheArquilliancontributorsJohnD.Amenthasalreadypublishedabookonthis topiccalledArquillianTestingGuide,PacktPublishing. Summary Inthischapter,wewentthroughacriticalpartofenterprisesystems:integrationtesting. Historically,onemaindownsideofJavaEEisitstestability,butArquillianhasreally solvedthisissuetoagreatextent. UsedasanextensiontotheJUnitframework,Arquillianexcelsincheckingtheintegration layerthatexposesthebusinesslogicinanenterpriseJavaapplication. Arquillianhooksintoyourtestingframeworktomanagethecontainer’slifecycle.Italso bundlesthetestclassintoadeployablearchivewithdependentclassesandresources. ThisisthelastchaptercoveringbasicJavaEEandWildFlyfeatures.Westartedwitha fewsessionbeans,andendedupwithwebsockets,anasynchronousmessagingsystem, RESTfulAPI,andevenalittlebitofJavaScript.Duringthecourseofthisbook,wesaw howthenewesteditionofJavaEEprovideduswithtoolstocreatemodernandscalable applications.Theplatform’sgoalistohelpthedevelopertofocusonthebusinesslogic. Thismeansremovingtheboilerplatecodethroughthewholeapplicationstackfromthe backendtotheviewlayer.Inmostareas,weonlycoveredthemostimportantfeaturesof themultipletechnologiesprovidedbyJavaEE.Thereisstillplentytoexplore! Intheappendix,wewilllearnafewthingsabouttheJBossForgetool,whichcangreatly increasetheproductivitywhenworkingwithJavaEE. AppendixA.RapidDevelopmentUsingJBoss Forge Intheappendixofthisbook,wewillgiveyouanoverviewofJBossForge,whichisa powerful,rapidapplicationdevelopment(aimedatJavaEE)andprojectcomprehension tool.WithForge,youcanstartanewprojectfromscratchandgeneratetheskeletonfor yourapplicationjustwithafewcommands.However,itcanalsobeusedforincremental enhancementsforyourexistingprojectsusingextraplugins. InstallingForge InordertoinstallForge,youneedtoperformthefollowingsteps: 1. DownloadandunzipForgefromhttp://forge.jboss.org/intoafolderonyourhard disk;thisfolderwillbeyourFORGE_HOME. 2. AddFORGE_HOME/bintoyourpath(Windows,Linux,andMacOSX). InUnix-basedoperatingsystems,thistypicallymeanseditingyour~/.bashrcor ~/.profile;youwillneedtoenterthefollowingcodesnippet: exportFORGE_HOME=~/forge/ exportPATH=$PATH:$FORGE_HOME/bin InWindowssystems,youwillneedtoopentheControlPanelwindow,thennavigateto SystemProperties|Advanced|EnvironmentVariables,andaddthesetwoentries visually.ItisrecommendedtosetuservariablesforForge,unlessyouhaveplacedthe unzippeddistributioninafolderwherealluserscanaccessit. Incaseofanyproblem,checkouttheonlineinstallationguideavailableat http://forge.jboss.org/document/installation. StartingForge InordertostartForge,thereisascriptnamedforge.bat(ortheequivalentForgefor Unix).Runthefollowingscript: forge.bat ThiswilllaunchtheForgeconsole,asshowninthefollowingscreenshot: Theconsoleacceptsalargesetofcommands,suchascommandstonavigateand manipulatethefilesystems,tocreatenewprojects,tooperateontheForgeenvironment andUIgeneration,andscaffoldingcommands.Italsoofferstheautocompletefeature. Inordertolearnthefollowingavailablecommandsincurrentcontext,presstheTabkey twice: [bin]$ aliasecho unaliasedit exportexit aboutgit-clone addon-build-and-installgrep addon-installless addon-install-from-gitls addon-listman addon-removemkdir archetype-addmore archetype-listopen archetype-removepl-cmil-forge-ecore-ui catproject-new cdpwd clearrm command-listrun config-clearsystem-property-get config-listsystem-property-set config-settouch connection-create-profiletrack-changes connection-remove-profiletransaction-start cpversion datewait Note Besidesthestandardcommands,itispossibletoenrichthesyntaxoftheForgecommand linewithadd-ons,whichaddssuperiorcapabilitiestoyourprojectcreation.On http://forge.jboss.org/addons,youcanfindalistofavailableplugins.Forexample,weare goingtousetheangular-jsplugininordertocreateaGUIforourapplication. Inthefollowingsection,wewilldemonstratehowtousesomeoftheavailablecommands inordertocreateaJavaEE7application. CreatingyourfirstJavaEE7application withJBossForge So,Forgeinstallationisquiteeasy;however,creatingyourfirstJavaEE7applicationwill beevenfaster!Although,wecancreateratheradvancedapplicationswithForge,forthe purposeoflearning,wewilljustuseasimpleschemathatcontainsausertable,whichcan bebuiltusingthefollowingcommand: CREATETABLEusers( idserialPRIMARYKEY, namevarchar(50), surnamevarchar(50), emailvarchar(50) ); Thefirstthingthatweneedtodoistocreateanewprojectusingtheproject-new command.ExecutethefollowingcommandsfromwithintheForgeshell: [bin]$project-new—namedforge-demo—topLevelPackage com.packtpub.wflydevelopment.appendix–projectFolderforge-demo Now,youhaveanewForgeproject,whichisbasedonaMavenprojectstructure. Arguably,generatinganewprojectisn’tForge’sgreatestvalue—thesamecanbeachieved withMavenarchetypes.ThesweetpartofForgeisthatnowyouhavetheluxuryof definingyourownapplicationskeletoninteractivelyafterithasalreadybeengenerated. ThismeansthatyoucancreatetheprojectusingtheMavenarchetypefirstandthenextend itusingForge’sintuitivesuggestions. Whentheprojectiscreated,youcanthenentercommand-listfromtheshell,asshownin thefollowingscreenshot,whichenlistsallthebasiccommandsthatyoucanuseinForge 2.12.1Final: Ifyouwanttolearnmoreaboutthesinglecommands,youcanusemanfollowedbythe commandname,asshowninthefollowingscreenshot: WhenyouhavelearnedhowtogethelpusingForge,let’sgetbacktoourapplication. Inthefirststep,weneedtospecifywhatJavaandJavaEEversionwewanttouse: [forge-demo]$project-set-compiler-version—sourceVersion1.8— targetVersion1.8 [forge-demo]$javaee-setup—javaEEVersion7 ***SUCCESS***JavaEE7hasbeeninstalled. Atthispoint,ourprojectalreadycontainsJavaEE7APIdependency.Now,sincewewill needtoreverse-engineerourdatabasetableintoJavaentities,thenextstepwillbeto configuretheJavaPersistenceAPI(JPA)layerforyourapplication.Thisapplication willbebasedonWildFlyJPAimplementation,whichisbasedontheHibernateprovider, referencingadatabasenamedForge.ThisdatabaseisreachableattheJavaNamingand DirectoryInterface(JNDI)namedjava:jboss/datasources/PostgreSqlDS.Thisis showninthefollowingcommandline: [forge-demo]$jpa-setup—jpaVersion2.1—providerHIBERNATE—container WILDFLY—dbTypePOSTGRES—dataSourceName java:jboss/datasources/PostgreSqlDS Thepersistence.xmlfilewasgenerated,andcurrentlytheconsoleindicatesthatweare editingit.Wecancheckitscontentbyusingthecatcommand: [persistence.xml]$cat. <?xmlversion=“1.0”encoding=“UTF-8”standalone=“yes”?> <persistencexmlns=“http://xmlns.jcp.org/xml/ns/persistence” xmlns:xsi=“http://w ww.w3.org/2001/XMLSchema-instance”version=“2.1” xsi:schemaLocation=“http://xmln s.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence _2_1.xsd”> <persistence-unitname=“forge-demo-persistence-unit”transactiontype=“JTA”> <description>ForgePersistenceUnit</description> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:jboss/datasources/PostgreSqlDS</jta-data-source> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <propertyname=“hibernate.hbm2ddl.auto”value=“create-drop”/> <propertyname=“hibernate.show_sql”value=“true”/> <propertyname=“hibernate.format_sql”value=“true”/> <propertyname=“hibernate.transaction.flush_before_completion” value=“true “/> <propertyname=“hibernate.dialect” value=“org.hibernate.dialect.PostgreSQL Dialect”/> </properties> </persistence-unit> </persistence> Next,wewillusethejpa-generate-entities-from-tablescommandinorderto generateyourEntityclass.YouwillneedtoprovidethefollowingJavaDatabase Connectivity(JDBC)connectioninformation: TheJDBCURL Theusernameandpassword TheSQLdialect TheJDBCdriverclassname ThepathinthefilesystemwheretheJDBCdriverislocated Thepackagewheretheentitieswillbegenerated Youcanspecifyalltheparametersinaone-linecommandorcompleteitinteractively.The finalcommandwouldlooklikethis(linebreaksaddedforreadability): [persistence.xml]$jpa-generate-entities-from-tables\ —jdbcUrljdbc:postgresql://localhost:5432/forge\ —hibernateDialectorg.hibernate.dialect.PostgreSQLDialect\ —userNamejboss\ —userPasswordjboss\ —driverLocationc:\forge\postgresql-9.3-1101.jdbc41.jar\ —driverClassorg.postgresql.Driver\ —databaseTablesusers Aftercompletingthepersistencelayer,wewillnowcreatetheGUIapplicationusingthe scaffoldcommand,whichcanbeassociatedwithseveralproviderssuchasthe AngularJSone.First,let’sinstalltheadd-onusingthefollowingshellcommand(notethat itshouldbeexecutedinyoursystem’sshell,notintheForgeCLI): forge—installorg.jboss.forge.addon:angularjs Aftertheinstallationiscomplete,weneedtoissuethreemorecommands.First,wewill preparethescaffoldingframework: [forge-demo]$scaffold-setup—providerAngularJS OurapplicationnowisawebappwithAngularJSlibraries.Next,wewilldefinethatwe wouldliketogenerateaUIfortheUsersentity: [forge-demo]$scaffold-generate—providerAngularJS—targets com.packtpub.wflydevelopment.appendix.model.Users Finally,wecreateanJAX-RSendpoint: [forge-demo]$rest-generate-endpoints-from-entities—targets com.packtpub.wflydevelopment.appendix.model.Users Andwearedone!TheapplicationisnowacompleteJavaEEapplicationwithREST endpoints,JPA,andanAngularJSUI. Note Whenthesesampleswerewritten,JBossForgedidnotfullysupportallJavaEE7 dependencies.Thiscanbefixedbymanuallymodifyingthepom.xmlfileofthegenerated project.Youshouldjustremoveallthedependenciesbesidestheoneshowninthe followingcodesnippet: <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> Additionally,ifyourUsersentitydoesn’[email protected] annotationinitsIDfield,makesureyouadditmanually(thereiscurrentlyabuginthe JPAadd-on): @Id @Column(name=“id”,unique=true,nullable=false) @GeneratedValue(strategy=GenerationType.IDENTITY) publicintgetId(){ returnthis.id; } Buildinganddeployingtheapplication Now,itistimetobuildyourapplicationusingthebuildcommand,whichwillcompile andpackageyourapplicationinawebapplicationarchive(forge-demo.war): [forge-demo]$build ***SUCCESS***BuildSuccess TheMavenbuildcommandhascreatedanartifactforge-demo-1.0.0-SNAPSHOT.warin thetargetfolderofyourproject.Youcannoweithermanuallycopythearchiveintothe deploymentsfolderofyourapplicationserverorusethemanagementinterfaces. Rememberthattheservershouldhavethejava:jboss/datasources/PostgreSqlDSdata sourcedefined! YourForge-demoapplicationinaction YoucanaccessyourapplicationatthedefaultURL,http://localhost:8080/forgedemo-1.0.0-SNAPSHOT/. Themainapplicationscreenwillcontainthelistofentitiesontheleftmenu.Ifyouchoose theUsersposition,thenyoushouldseealistofusersthathavebeenadded,aSearch buttonwhichcanbeusedtofilteracrosstheusers,andaCreatebutton,whichobviously willinsertsomedata.Thisisshowninthefollowingscreenshot: ByclickingontheCreatebutton,youwillbetakentothescreenthatallowstheinsertion ofanewusertothedatabase(rememberthatwehaveconfiguredthisapplicationtorun againstaPostgreSQLdatabase).Thisisshowninthefollowingscreenshot: Inthisway,wehavecreatedabasicAngularJSappbasedonJavaEE.Itcanbeusedasa foundationforyourprojectorjustasandboxinwhichyoucantryoutnewideas.Besure tocheckoutotheravailableadd-ons,andrememberthatyouwillalwayshavethe possibilitytocreateyourownones! Index A —all-server-groupsflag/Deployingtoallservergroups @ApplicationScopedscope/CDIscopes a4j$poll/Makingyourapplicationrich acknowledgmentmode/Transactionandacknowledgmentmodes ActiveMQ andHornetQintegration/Areal-worldexample–HornetQandActiveMQ integration ActiveMQbroker URL/Areal-worldexample–HornetQandActiveMQintegration ActiveMQmessages consuming/ConsumingActiveMQmessages ActiveMQplugin URL/ConsumingActiveMQmessages ActiveMQresourceadapter installing/InstallingtheActiveMQresourceadapter Administrationtab/Launchingthewebconsole administrativeoperations auditing/Auditingadministrativeoperations advancedlanguages used,forcreatingpowerfulCLIscripts/Usingadvancedlanguagestocreate powerfulCLIscripts angular-jsplugin/StartingForge AngularJS URL/AddingAngularJS AngularJS adding/AddingAngularJS AngularUIBootStrappackage URL/AddingAngularJS ApacheCXF,features URL/JBossSOAP-basedwebservicesstack app-nameelement/CreatingaremoteEJBclient application running/Gettingreadytoruntheapplication,Runningtheapplication scheduler,combininginto/Combiningtheschedulerintoourapplication persistence,addingto/Addingpersistencetoourapplication queries,codingfor/Codingqueriesforyourapplication services,addingto/Addingservicestoyourapplication message-drivenbeans,addingto/Addingmessage-drivenbeanstoyour application compiling/Compilinganddeployingtheapplication deploying/Compilinganddeployingtheapplication deploying,toseveralWildFlynodes/Deployinganapplicationtoseveral WildFlynodes Databaseloginmodule,using/UsingtheDatabaseloginmoduleinyour application applications deploying,command-lineinterfaceused/Deployingapplicationsusingthe command-lineinterface deploying,todomain/Deployingapplicationstoadomain deploying,CLIused/DeployingapplicationsusingtheCLI deploying,toWildFlydomain/DeployingapplicationstoaWildFlydomain deploying,toallservergroups/Deployingtoallservergroups deploying,tosingleservergroup/Deployingtoasingleservergroup applicationserver managing/Managingtheapplicationserver WildFly8,managingwithwebinterface/ManagingWildFly8withtheweb interface applicationservernodes/WildFly8coreconcepts Arquillian about/Instrumentsusedfortesting,GettingstartedwithArquillian test,writing/WritinganArquilliantest pom.xmlfile,configuring/Configuringthepom.xmlfile firstArquilliantest,writing/WritingyourfirstArquilliantest TicketTest,running/RunningArquillianTicketTest testsrunning,Spockused/RunningArquilliantestsusingSpock ShrinkWrapResolver/ShrinkWrapResolver ShrinkWrapDescriptors/ShrinkWrapDescriptors persistence,testing/Persistencetesting WebSockets,testing/WebSocketstesting test,enhancing/EnhancingyourArquilliantest URL/Additionalinformation ArquillianPersistenceExtensionmanual URL/Persistencetesting ArquillianSpocktestrunner URL/RunningArquilliantestsusingSpock ArquillianSuiteExtension about/Additionalinformation Arquilliantest writing/WritinganArquilliantest enhancing/EnhancingyourArquilliantest Arquilliantests running,Spockused/RunningArquilliantestsusingSpock ArquillianTicketTest running/RunningArquillianTicketTest ArquillianWarp/ArquillianWarp URL/ArquillianWarp AssertJ/ShrinkWrapResolver asymmetricencryption/Securingthetransportlayer asynchronously/AshortintroductiontoJMS asynchronousmethods adding,toEJBs/AddingasynchronousmethodstoourEJBs fire-and-forgetasynchronouscalls,using/Usingfire-and-forgetasynchronous calls Futureobject,returningtoclient/ReturningaFutureobjecttotheclient audit-logconfiguration about/Auditingadministrativeoperations Formatter/Auditingadministrativeoperations Handler/Auditingadministrativeoperations Logger/Auditingadministrativeoperations authentication/ApproachingtheJavasecurityAPI versusauthorization/ApproachingtheJavasecurityAPI authorization/ApproachingtheJavasecurityAPI versusauthentication/ApproachingtheJavasecurityAPI Auto-deployExplodedattribute/Changingthedeploymentscannerproperties Auto-deployZippedattribute/Changingthedeploymentscannerproperties autoApplyattribute/AddingBeanValidation automatictimers/UsingtheEJBtimerservice AUTO_ACKNOWLEDGE/Transactionandacknowledgmentmodes B BatchapplicationstheJavaPlatform1.0(JSR352)/BatchapplicationsfortheJava Platform1.0–JSR352 batchingframework about/Theoverviewofthebatchingframework Chunksteps/Theoverviewofthebatchingframework Tasksteps/Theoverviewofthebatchingframework firstbatchjob/Ourfirstbatchjob concurrencyutilities,usinginJavaEE/UsingconcurrencyutilitiesinJavaEE bean-discovery-modeattribute/WildFlyCDIimplementation bean-managedconcurrency using/Usingbean-managedconcurrency bean-nameelement/CreatingaremoteEJBclient beanconcurrency controlling/Controllingbeanconcurrency bean-managedconcurrency,using/Usingbean-managedconcurrency beans creating/Creatingthebeans view,building/Buildingtheview application,running/Gettingreadytoruntheapplication scheduler,combiningintoapplication/Combiningtheschedulerintoour application BeanValidation adding/AddingBeanValidation BeanValidation(JSR-303)/AddingBeanValidation Beanvalidation1.1(JSR349)/BeanValidation1.1–JSR349 Behavior-drivendevelopment(BDD)/RunningArquilliantestsusingSpock BillofMaterials(BOM)/InstallingRichFaces bookSeatmethod/Addingservicestoyourapplication bookTicketmethod/AddingAngularJS Bootstrap about/CodingtheJSFview URL/CodingtheJSFview bottom-upapproach/StrategiestobuildSOAP-basedwebservices browsersupport,WebSockets URL/HowdoWebSocketswork buildingblocks,JMS connectionfactory/ThebuildingblocksofJMS connection/ThebuildingblocksofJMS session/ThebuildingblocksofJMS messageproducer/ThebuildingblocksofJMS messageconsumer/ThebuildingblocksofJMS built-inroles about/Role-basedsecurity Monitor/Role-basedsecurity Operator/Role-basedsecurity Maintainer/Role-basedsecurity Deployer/Role-basedsecurity Administrator/Role-basedsecurity Auditor/Role-basedsecurity SuperUser/Role-basedsecurity buyTicketmethod/CodingourEJBapplication C @ConversationScopedscope/CDIscopes CDI about/AnoverviewofJavaEEandWildFly,ContextsandDependency InjectionforJavaEE1.1–JSR346,IntroducingContextsandDependency Injection namedbeans/Namedbeans scopes/CDIscopes WildFlyCDIimplementation/WildFlyCDIimplementation ticketingsystem,rethinking/Rethinkingyourticketingsystem beans,creating/Creatingthebeans CDIforJavaEE1.1(JSR346)/ContextsandDependencyInjectionforJavaEE1.1 –JSR346 CDIReferenceImplementation URL/CDIscopes certificate-signingrequest(CSR)/SecuringHTTPcommunicationwithacertificate signedbyaCA certificatemanagementtools/Certificatemanagementtools CertificationAuthority(CA)/Securingthetransportlayer Chef URL/LaunchingtheCLI chunk-basedbatchstep creating/Creatingachunk-basedbatchstep Chunksteps/Theoverviewofthebatchingframework CLIcommands constructing/ConstructingCLIcommands CLIcommands,constructing resourceaddress,determining/Determiningtheresourceaddress operations,performingonresources/Performingoperationsonresources client Futureobject,returningto/ReturningaFutureobjecttotheclient clientapplication running/Runningtheclientapplication userauthentication,adding/Addinguserauthentication expanding/Expandingourclientapplication POJOs,transformingtoJSON/TransformingPOJOstoJSON clientcertificate generating/Generatingtheserverandclientcertificates clientcomponents installing/Installingtheserverandclientcomponents CLIENT_ACKNOWLEDGES/Transactionandacknowledgmentmodes CLIexecution wrapping,scriptinglanguagesused/UsingscriptinglanguagestowrapCLI execution CLIscripts creating/CreatingCLIscripts application,deployingtoseveralWildFlynodes/Deployinganapplicationto severalWildFlynodes servers,restartingindomain/Restartingserversinadomain datasource,installingasmodule/Installingadatasourceasamodule JMSresources,adding/AddingJMSresources creating,advancedlanguagesused/Usingadvancedlanguagestocreate powerfulCLIscripts scriptinglanguages,usedforwrappingCLIexecution/Usingscripting languagestowrapCLIexecution cluster-awareremoteclient coding/Codingthecluster-awareremoteclient clusteredapplications deploying/Deployingclusteredapplications HAStatefulSessionBean(SFSB),creating/CreatingHAStatefulSession Beans clustering about/Clusteringbasics benefits/Clusteringbasics clustering,benefits horizontalscalability(scalingout)/Clusteringbasics loadbalancing/Clusteringbasics highavailability/Clusteringbasics command-lineinterface used,fordeployingapplications/Deployingapplicationsusingthecommandlineinterface used,forcreatingnewdatasource/Usingthecommand-lineinterfacetocreate anewdatasource command-lineinterface(CLI) used,forconnectingtoserver/Connectingtotheserverwiththecommand-line interface about/Connectingtotheserverwiththecommand-lineinterface concurrencyutilities used,inJavaEE/UsingconcurrencyutilitiesinJavaEE concurrencyutilities(JSR236)/ConcurrencyutilitiesforJavaEE1.0–JSR236 concurrencyutilities,components ManagedExecutorService/UsingconcurrencyutilitiesinJavaEE ManagedScheduledExecutorService/UsingconcurrencyutilitiesinJavaEE ContextService/UsingconcurrencyutilitiesinJavaEE ManagedThreadFactory/UsingconcurrencyutilitiesinJavaEE connectcommand/LaunchingtheCLI,UsingscriptinglanguagestowrapCLI execution connection/ThebuildingblocksofJMS connectionfactories creating/Creatingandusingconnectionfactories using/Creatingandusingconnectionfactories connectionfactory/ThebuildingblocksofJMS console webservice,inspectingfrom/Inspectingthewebservicefromtheconsole constraints URL/AddingBeanValidation container,JavasecurityAPI declarativesecurity/ApproachingtheJavasecurityAPI about/ApproachingtheJavasecurityAPI containeradapters Embedded/Configuringthepom.xmlfile Managed/Configuringthepom.xmlfile Remote/Configuringthepom.xmlfile contextual/IntroducingContextsandDependencyInjection ContinuousIntegration(CI)/LaunchingtheCLI controller adding,fordrivinguserrequests/Addingacontrollertodriveuserrequests core-threads,executorservice/UsingconcurrencyutilitiesinJavaEE createSeatTypemethod/Addingservicestoyourapplication CriteriaAPI/Codingqueriesforyourapplication D @Dependentscope/CDIscopes database settingup/Settingupthedatabase Databaseloginmodule about/TheWildFlysecuritysubsystem creating/CreatingaDatabaseloginmodule passwords,encrypting/Encryptingpasswords using,inapplication/UsingtheDatabaseloginmoduleinyourapplication datapersistence about/Datapersistencemeetsthestandard JPA,workingwith/WorkingwithJPA datasource installing,asmodule/Installingadatasourceasamodule datasource creating,command-lineinterfaceused/Usingthecommand-lineinterfaceto createanewdatasource declarativesecurity/ApproachingtheJavasecurityAPI demoapplication,Forge/YourForge-demoapplicationinaction deploycommand/DeployingapplicationsusingtheCLI deploymentscannerproperties changing/Changingthedeploymentscannerproperties Deploymenttimeoutattribute/Changingthedeploymentscannerproperties deployshellcommand/Deployingapplicationsusingthecommand-lineinterface detypedAPI used,forcreatingresourcewatches/Creatingyourresourcewatchesusingthe detypedAPI developmentenvironments IntelliJIDEA/Alternativedevelopmentenvironments NetBeans/Alternativedevelopmentenvironments digitalcertificate/Securingthetransportlayer disallowedactivities URL/EJB3.2–anoverview Dispatchermodule/AbrieflookattheJAXWSarchitecture distinct-nameelement/CreatingaremoteEJBclient doCleanUpmethod/Addingservicestoyourapplication domain controller/WildFly8coreconcepts HostController/WildFly8coreconcepts applicationservernodes/WildFly8coreconcepts applications,deployingto/Deployingapplicationstoadomain servers,restartingin/Restartingserversinadomain domaincluster/WildFlyclustering domainconfiguration URL/ManagingWildFly8withthewebinterface domaincontroller/WildFly8coreconcepts domaindirectorystructure about/TheWildFly8directorylayout configuration/TheWildFly8directorylayout data/content/TheWildFly8directorylayout Log/TheWildFly8directorylayout servers/TheWildFly8directorylayout tmp/TheWildFly8directorylayout domainnodescluster initiating/Startingaclusterofdomainnodes domaincontrollerconfiguration/Thedomaincontrollerconfiguration hostconfigurations/Hostconfigurations DomainSpecificLanguage(DSL)/RunningArquilliantestsusingSpock Drone about/Additionalinformation drop-and-createvalue/Configuringpersistence DUPS_OK_ACKNOWLEDGE/Transactionandacknowledgmentmodes durablesubscription/AshortintroductiontoJMS E EAP using,withWildFly/WildFlyandEnterpriseApplicationPlatform about/WildFlyandEnterpriseApplicationPlatform Alpha/WildFlyandEnterpriseApplicationPlatform Beta/WildFlyandEnterpriseApplicationPlatform Final/WildFlyandEnterpriseApplicationPlatform Eclipse URL/InstallingtheEclipseenvironment Eclipse,withPyDevextension URL/UsingscriptinglanguagestowrapCLIexecution Eclipsedeploymentoptions about/AdvancedEclipsedeploymentoptions managing,withwebconsole/Managingdeploymentswiththewebconsole Eclipseenvironment installing/InstallingtheEclipseenvironment Eclipseenvironmentinstallation about/InstallingtheEclipseenvironment JBossTools,installing/InstallingJBossTools EJB about/EJB3.2–anoverview EJB3StatelessSessionBean(SLSB)webservices/EJB3StatelessSessionBean (SLSB)webservices EJBapplication coding/CodingourEJBapplication deploying/DeployingtheEJBapplication EJBclient coding/CodingtheEJBclient configuration,adding/AddingtheEJBclientconfiguration EJBcommunication securing/SecuringEJBcommunication EJBmodule/DevelopingsingletonEJBs EJBprojectobjectmodule(pom.xml) configuring/ConfiguringtheEJBprojectobjectmodule(pom.xml) EJBs asynchronousmethods,addingto/AddingasynchronousmethodstoourEJBs about/AreEJBsandJSFManagedBeansobsolete? securing/SecuringEJBs webservices,securing/Securingwebservices EJBtimers programmatictimers/UsingtheEJBtimerservice automatictimers/UsingtheEJBtimerservice EJBtimerservice using/UsingtheEJBtimerservice timer,creating/Programmatictimercreation timerevents,scheduling/Schedulingtimerevents EJBtypes sessionbeans/EJB3.2–anoverview Message-drivenbeans(MDB)/EJB3.2–anoverview entityobjects/EJB3.2–anoverview Enabledattribute/Changingthedeploymentscannerproperties encryption symmetricencryption/Securingthetransportlayer asymmetricencryption/Securingthetransportlayer endpoint URL/Creatingourfirstendpoint EndpointConfigparameter/Creatingourfirstendpoint EnterpriseApplicationIntegration(EAI)/UsingJMStointegratewithexternal systems Enterprisearchive/DevelopingsingletonEJBs enterprisebeans threads,introducingto/Introducingthreadstoenterprisebeans EnterpriseJavaBeans(EJB)/AnoverviewofJavaEEandWildFly,Thedomain controllerconfiguration EnterpriseJavaBeans3.2(JSR345)/EnterpriseJavaBeans3.2–JSR345 entities adding/Cookingentities EntityManage/Addingproducerclasses entityobjects/EJB3.2–anoverview example running/Runningtheexample executorservice,properties core-threads/UsingconcurrencyutilitiesinJavaEE max-threads/UsingconcurrencyutilitiesinJavaEE keepalive-time/UsingconcurrencyutilitiesinJavaEE hung-task-threshold/UsingconcurrencyutilitiesinJavaEE ExpressionLanguage(EL)/Creatingthebeans ExpressionLanguage(UEL)/Namedbeans externalsystems JMSused,forintegratingwith/UsingJMStointegratewithexternalsystems F FacesContext/Addingproducerclasses FacesFlow about/Gettingreadytoruntheapplication features,WildFly/NewfeaturesinWildFly fetchattribute/Cookingentities filters adding/Addingfilters fire-and-forgetasynchronouscalls using/Usingfire-and-forgetasynchronouscalls firstapplication deploying,toWildFly8/DeployingyourfirstapplicationtoWildFly8 firstArquilliantest writing/WritingyourfirstArquilliantest firstbatchjob about/Ourfirstbatchjob chunk-basedbatchstep,creating/Creatingachunk-basedbatchstep job-basedbatchstep,creating/Creatingajob-basedbatchstep firstendpoint creating/Creatingourfirstendpoint firstloginmodule settingup/Settingupyourfirstloginmodule Forge installing/InstallingForge URL/InstallingForge,StartingForge initiating/StartingForge used,forcreatingJavaEE7application/CreatingyourfirstJavaEE7 applicationwithJBossForge demoapplication/YourForge-demoapplicationinaction FORM-basedsecurity switchingto/SwitchingtoFORM-basedsecurity fully-qualified-classname-of-the-remote-interfaceelement/CreatingaremoteEJB client Futureobject returning,toclient/ReturningaFutureobjecttotheclient G @GeneratedValueannotation/Cookingentities @GETannotation/AccessingRESTresources getPortmethod/Developingawebserviceconsumer getSeatmethod/CodingourEJBapplication getSeatPricemethod/CodingourEJBapplication getSeatsmethod/EJB3StatelessSessionBean(SLSB)webservices givenconstruction/RunningArquilliantestsusingSpock GoogleGuice URL/IntroducingContextsandDependencyInjection GoogleWebToolkit(GWT)/ManagingWildFly8withthewebinterface Graphene about/Additionalinformation graphicalmode CLI,usedin/UsingaCLIinthegraphicalmode H HA achieving,programmingconsiderations/Programmingconsiderationsto achieveHA achieving,inJSFapplications/AchievingHAinJSFapplications hashingalgorithms URL/Encryptingpasswords HAStatefulSessionBean(SFSB),creating about/CreatingHAStatefulSessionBeans Ticketexample,clustering/ClusteringtheTicketexample cache,convertingtodistributedcache/Turningyourcacheintoadistributed cache cluster-awareremoteclient,coding/Codingthecluster-awareremoteclient highavailability,deploying/Deployingandtestinghighavailability highavailability,testing/Deployingandtestinghighavailability hawt.ioconsole URL/ConsumingActiveMQmessages HornetQ URL/TheJBossmessagingsubsystem andActiveMQintegration/Areal-worldexample–HornetQandActiveMQ integration HornetQdocumentation URL/Specifyingwhichmessagetoreceiveusingselectors HostController/WildFly8coreconcepts HTTPcommunication securing,withself-signedcertificate/SecuringtheHTTPcommunicationwitha self-signedcertificate securing,withcertificatesignedbyCA/SecuringHTTPcommunicationwitha certificatesignedbyaCA hung-task-threshold,executorservice/UsingconcurrencyutilitiesinJavaEE I Infinispan/WildFlyclustering instruments used,fortesting/Instrumentsusedfortesting integrationtest/Testtypes IntelliJIDEA URL/Alternativedevelopmentenvironments about/Alternativedevelopmentenvironments interceptors creating/Creatinginterceptors InVmConnectionFactory/Creatingandusingconnectionfactories IRC URL/Additionalinformation IronJacamar URL/InstallingtheActiveMQresourceadapter item-countattribute/Creatingachunk-basedbatchstep ItemWriterclass/Creatingachunk-basedbatchstep J @javax.annotation.security.DenyAllannotation/SecuringEJBs @javax.annotation.security.PermitAllannotation/SecuringEJBs @javax.annotation.security.RolesAllowedannotation/SecuringEJBs @javax.annotation.security.RunAsannotation/SecuringEJBs java.util.Logger/Addingproducerclasses JavaAPIforJSONprocessing1.0(JSR353)/JavaAPIforJSONProcessing1.0– JSR353 JavaAPIforRESTfulWebServices(JAX-RS)/AnoverviewofJavaEEand WildFly JavaAPIforWebSocket1.0(JSR356)/JavaAPIforWebSocket1.0–JSR356 JavaAPIforXMLWebServices(JAX-WS)/AnoverviewofJavaEEandWildFly JavaConnectorArchitecture(JCA)/UsingJMStointegratewithexternalsystems Javadatabaseconnectivity(JDBC)/CreatingyourfirstJavaEE7applicationwith JBossForge JavaEE overview/AnoverviewofJavaEEandWildFly CDIforJavaEE1.1(JSR346)/ContextsandDependencyInjectionforJava EE1.1–JSR346 JavaServletAPI3.1(JSR340)/JavaServletAPI3.1–JSR340 concurrencyutilities,usingin/UsingconcurrencyutilitiesinJavaEE threads,introducingtoenterprisebeans/Introducingthreadstoenterprisebeans JavaEE7 about/WelcometoJavaEE7 JavaServerFaces2.2(JSR344)/JavaServerFaces2.2–JSR344 EnterpriseJavaBeans3.2(JSR345)/EnterpriseJavaBeans3.2–JSR345 JavaPersistenceAPI2(JSR338)/JavaPersistenceAPI2.1–JSR338 JAX-RS2.0(JSR339)/JAX-RS,theJavaAPIforRESTfulWebServices2.0– JSR339 JavaMessageService2.0(JSR343)/JavaMessageService2.0–JSR343 Beanvalidation1.1(JSR349)/BeanValidation1.1–JSR349 concurrencyutilities(JSR236)/ConcurrencyutilitiesforJavaEE1.0–JSR 236 BatchapplicationstheJavaPlatform1.0(JSR352)/Batchapplicationsforthe JavaPlatform1.0–JSR352 JavaAPIforJSONprocessing1.0(JSR353)/JavaAPIforJSONProcessing 1.0–JSR353 JavaAPIforWebSocket1.0(JSR356)/JavaAPIforWebSocket1.0–JSR356 JavaEE7application creating,withForge/CreatingyourfirstJavaEE7applicationwithJBossForge building/Buildinganddeployingtheapplication deploying/Buildinganddeployingtheapplication JavaMessageService1.1(JMS)/Areal-worldexample–HornetQandActiveMQ integration JavaMessageService2.0(JSR343)/JavaMessageService2.0–JSR343 JavaMessagingService(JMS)/AnoverviewofJavaEEandWildFly JavaNamingandDirectoryInterface(JNDI)/CreatingHAStatefulSessionBeans, CreatingyourfirstJavaEE7applicationwithJBossForge JavaNamingDirectoryIndex(JNDI)/Creatingandusingconnectionfactories JavaPersistenceAPI(JPA)/AnoverviewofJavaEEandWildFly,Datapersistence meetsthestandard,CreatingyourfirstJavaEE7applicationwithJBossForge JavaPersistenceAPI2.1(JSR338)/JavaPersistenceAPI2.1–JSR338 JavaPersistenceQueryLanguage(JPQL)/Datapersistencemeetsthestandard JavaSE installing/InstallingJavaSE JavaSecureSocketExtension(JSSE)/EnablingtheSecureSocketLayeronWildFly JavasecurityAPI about/ApproachingtheJavasecurityAPI authentication/ApproachingtheJavasecurityAPI authorization/ApproachingtheJavasecurityAPI programmaticsecurity/ApproachingtheJavasecurityAPI WildFlysecuritysubsystem/TheWildFlysecuritysubsystem firstloginmodule,settingup/Settingupyourfirstloginmodule loginmodule,usinginTicketwebapplication/Usingtheloginmoduleinthe Ticketwebapplication FORM-basedsecurity,switchingto/SwitchingtoFORM-basedsecurity Databaseloginmodule,creating/CreatingaDatabaseloginmodule EJBs,securing/SecuringEJBs JavaSEinstallation URL/InstallingJavaSE testing/Testingtheinstallation WildFly,installing/InstallingWildFly WildFly,initializing/StartingWildFly server,connectingwithcommand-lineinterface/Connectingtotheserverwith thecommand-lineinterface WildFly,terminating/StoppingWildFly WildFly,restarting/RestartingWildFly JavaServerFaces(JSFs)/AnoverviewofJavaEEandWildFly JavaServerFaces2.2-JSR344/JavaServerFaces2.2–JSR344 JavaServerPages(JSP) about/Buildingtheview JavaServerPages(JSPs)/AnoverviewofJavaEEandWildFly JavaServletAPI3.1(JSR340)/JavaServletAPI3.1–JSR340 JAX-RS activating/ActivatingJAX-RS JAX-RS2.0 about/DevelopingREST-basedwebservices JAX-RS2.0(JSR339)/JAX-RS,theJavaAPIforRESTfulWebServices2.0–JSR 339 JAX-RSClientFramework/JBossRESTwebservices JAXWSarchitecture/AbrieflookattheJAXWSarchitecture JBeret URL/Ourfirstbatchjob JBossEJBClient/CreatingHAStatefulSessionBeans JBossJIRA URL/Additionalinformation JBossmessagingsubsystem/TheJBossmessagingsubsystem JBossRESTwebservices about/JBossRESTwebservices JAX-RS,activating/ActivatingJAX-RS REST,addingtoticketexample/AddingRESTtoourticketexample filters,adding/Addingfilters RESTservice,consuming/ConsumingourRESTservice ticketexample,compiling/Compilingourticketexample AngularJS,adding/AddingAngularJS JBossSOAP-basedwebservicesstack/JBossSOAP-basedwebservicesstack JBossTools installing/InstallingJBossTools URL/InstallingJBossTools JDBCdriver installing,inWildFly/InstallingtheJDBCdriverinWildFly command-lineinterfaceused,forcreatingnewdatasource/Usingthe command-lineinterfacetocreateanewdatasource JEE URL/EJB3.2–anoverview JGroupslibrary/WildFlyclustering JMS about/AshortintroductiontoJMS buildingblocks/ThebuildingblocksofJMS JBossmessagingsubsystem/TheJBossmessagingsubsystem connectionfactories,creating/Creatingandusingconnectionfactories connectionfactories,using/Creatingandusingconnectionfactories destinations,using/UsingJMSdestinations message-drivenbeans,addingtoapplication/Addingmessage-drivenbeansto yourapplication transactionmode/Transactionandacknowledgmentmodes acknowledgmentmode/Transactionandacknowledgmentmodes used,forintegratingwithexternalsystems/UsingJMStointegratewith externalsystems HornetQandActiveMQ,integration/Areal-worldexample–HornetQand ActiveMQintegration JMSAPI about/AshortintroductiontoJMS persistentdeliverymode/AshortintroductiontoJMS nonpersistentdeliverymode/AshortintroductiontoJMS JMSdestination Durableoption/UsingJMSdestinations Selectoroption/UsingJMSdestinations JMSdestinations using/UsingJMSdestinations JMSproducer adding/AddingtheJMSproducer JMSresources adding/AddingJMSresources JMSspecification,messages synchronously/AshortintroductiontoJMS asynchronously/AshortintroductiontoJMS job-basedbatchstep creating/Creatingajob-basedbatchstep JobOperatorstartmethod/Creatingachunk-basedbatchstep Jolokia URL/CreatingyourresourcewatchesusingthedetypedAPI JPA workingwith/WorkingwithJPA NativeSQL/Codingqueriesforyourapplication JavaPersistenceQueryLanguage(JPQL)/Codingqueriesforyourapplication CriteriaAPI/Codingqueriesforyourapplication JPAQueryLanguage(JPQL)/JavaPersistenceAPI2.1–JSR338 JSF2facetsuggestions/JSF2facetsuggestions JSFManagedBeans about/AreEJBsandJSFManagedBeansobsolete? JSFview coding/CodingtheJSFview JSON URL/AddingRESTtoourticketexample POJOs,transformingto/TransformingPOJOstoJSON JSR-107/WildFlyclustering JSR-339 URL/DevelopingREST-basedwebservices JUnit URL/WritinganArquilliantest Jythoninstaller URL/UsingscriptinglanguagestowrapCLIexecution K keepalive-time,executorservice/UsingconcurrencyutilitiesinJavaEE keytool/Certificatemanagementtools Kryo URL/TransformingPOJOstoJSON L localbusinessinterface/EJB3.2–anoverview loginmodule used,inTicketwebapplication/UsingtheloginmoduleintheTicketweb application M @Modelstereotype/Makingyourapplicationrich managedexecutorservices advantages,overstandardones/UsingconcurrencyutilitiesinJavaEE ManagedTaskinterface/Introducingthreadstoenterprisebeans managementmodeldescriptions reading,viarawmanagementAPI/Readingmanagementmodeldescriptions viatherawmanagementAPI mappedByattribute/Cookingentities Maven installing/InstallingMaven Mavenbuildcommand/Buildinganddeployingtheapplication Mavenconfiguration adding/AddingtheMavenconfiguration Maveninstallation about/InstallingMaven URL/InstallingMaven references/InstallingMaven testing/Testingtheinstallation Mavenproject creating/Rethinkingyourticketingsystem,CreatingtheMavenproject Mavenconfiguration,adding/AddingtheMavenconfiguration entities,adding/Cookingentities BeanValidation,adding/AddingBeanValidation Mavenprojects benefits/DevelopingsingletonEJBs Mavenrepository URL/Areal-worldexample–HornetQandActiveMQintegration max-threads,executorservice/UsingconcurrencyutilitiesinJavaEE MDBinstancelifecycle,states DoesnotExist/Addingmessage-drivenbeanstoyourapplication MethodreadyPool/Addingmessage-drivenbeanstoyourapplication message-drivenbeans adding,toapplication/Addingmessage-drivenbeanstoyourapplication advantages/Addingmessage-drivenbeanstoyourapplication implementing/Cookingmessage-drivenbeans JMSproducer,adding/AddingtheJMSproducer application,deploying/Compilinganddeployingtheapplication application,compiling/Compilinganddeployingtheapplication messageselectors,specifying/Specifyingwhichmessagetoreceiveusing selectors Message-drivenbeans(MDB)/EJB3.2–anoverview Message-drivenbeans(MDBs) about/Addingmessage-drivenbeanstoyourapplication messageconsumer/ThebuildingblocksofJMS messageproducer/ThebuildingblocksofJMS messageselectors specifying/Specifyingwhichmessagetoreceiveusingselectors module-nameelement/CreatingaremoteEJBclient multicast/WildFlyclustering N nameattribute/Changingthedeploymentscannerproperties,Configuring persistence namedbeans/Namedbeans NativeSQL/Codingqueriesforyourapplication NetBeans URL/Alternativedevelopmentenvironments NewInput-Output(NIO)/TheJBossmessagingsubsystem newuser creating,details/ManagingWildFly8withthewebinterface No-interfaceview/EJB3.2–anoverview nondurablesubscription/AshortintroductiontoJMS nonpersistentdeliverymode/AshortintroductiontoJMS notations,resourceaddress node-type/Determiningtheresourceaddress node-name/Determiningtheresourceaddress O @OnCloseannotation/Creatingourfirstendpoint @OnErrorannotation/Creatingourfirstendpoint @OneToManyannotation/Cookingentities @OnMessageannotation/Creatingourfirstendpoint @OnOpenannotation/Creatingourfirstendpoint @org.jboss.ejb3.annotation.SecurityDomainannotation/SecuringEJBs observer about/Creatingthebeans operations performing,onresources/Performingoperationsonresources overridingpools,beans URL/Addingmessage-drivenbeanstoyourapplication P @Producerannotation advantages/Creatingthebeans PageObject about/Additionalinformation passwords encrypting/Encryptingpasswords pathattribute/Changingthedeploymentscannerproperties PathRelativetoattribute/Changingthedeploymentscannerproperties persistence adding,toapplication/Addingpersistencetoourapplication database,settingup/Settingupthedatabase JDBCdriver,installinginWildFly/InstallingtheJDBCdriverinWildFly configuring/Configuringpersistence producerclasses,adding/Addingproducerclasses queries,codingforapplication/Codingqueriesforyourapplication services,addingtoapplication/Addingservicestoyourapplication controller,addingtodriveuserrequests/Addingacontrollertodriveuser requests JSFview,coding/CodingtheJSFview example,running/Runningtheexample testing/Persistencetesting persistentdeliverymode/AshortintroductiontoJMS PlainOldJavaObject(POJO)/Datapersistencemeetsthestandard,Creatingour firstendpoint PlainOldJavaObjects(POJOs)/TheJBossmessagingsubsystem plugin,forJBoss URL/CreatingyourresourcewatchesusingthedetypedAPI point-to-point(PTP)/ThebuildingblocksofJMS POJOs transforming,toJSON/TransformingPOJOstoJSON POJOwebservice developing/DevelopingaPOJOwebservice pom.xmlfile configuring/Configuringthepom.xmlfile PostgreSQLdatabase URL/Addingpersistencetoourapplication PostgreSQLJDBCdriver URL/InstallingtheJDBCdriverinWildFly producerclasses adding/Addingproducerclasses profiles,WildFlydomain default/Thedomaincontrollerconfiguration full/Thedomaincontrollerconfiguration ha/Thedomaincontrollerconfiguration full-ha/Thedomaincontrollerconfiguration programmaticsecurity/ApproachingtheJavasecurityAPI programmatictimers/UsingtheEJBtimerservice projectobjectmodule,client configuring/Configuringtheclient’sprojectobjectmodule public-keycryptography/Securingthetransportlayer publish/subscribe(pub/sub)/ThebuildingblocksofJMS Puppet URL/LaunchingtheCLI Q queries coding,forapplication/Codingqueriesforyourapplication queues about/ThebuildingblocksofJMS R @RequestScopedscope/CDIscopes ra.xmlfile/InstallingtheActiveMQresourceadapter rar-infocommandshell/InstallingtheActiveMQresourceadapter rawmanagementAPI used,formanagingapplicationserver/UsingtherawmanagementAPIto managetheapplicationserver managementmodeldescriptions,readingvia/Readingmanagementmodel descriptionsviatherawmanagementAPI resourcewatchescreating,detypedAPIused/Creatingyourresourcewatches usingthedetypedAPI read-resourcecommand/Performingoperationsonresources readItemmethod/Creatingachunk-basedbatchstep RealmDirectloginmodule/TheWildFlysecuritysubsystem receive()method/AshortintroductiontoJMS remote.connectionsproperty/AddingtheEJBclientconfiguration remotebusinessinterface/EJB3.2–anoverview RemoteConnectionFactory/Creatingandusingconnectionfactories remoteEJBclient creating/CreatingaremoteEJBclient projectobjectmodule,configuring/Configuringtheclient’sprojectobject module EJBclient,coding/CodingtheEJBclient clientapplication,running/Runningtheclientapplication EJBtimerservice,using/UsingtheEJBtimerservice asynchronousmethods,addingtoEJBs/Addingasynchronousmethodstoour EJBs remotehosts connectingfrom/Connectingfromremotehosts RemoteProcedureCall/DevelopingaPOJOwebservice requireddependencies adding/Addingtherequireddependencies resourceadaptermodule/DevelopingsingletonEJBs resourceaddress determining/Determiningtheresourceaddress resources operations,performingon/Performingoperationsonresources tabcompletionhelper,using/Usingthetabcompletionhelper resourcewatches creating,detypedAPIused/Creatingyourresourcewatchesusingthedetyped API REST adding,toticketexample/AddingRESTtoourticketexample REST-basedwebservices developing/DevelopingREST-basedwebservices RESTresources,accessing/AccessingRESTresources JBossRESTwebservices/JBossRESTwebservices RESTresources accessing/AccessingRESTresources RESTservice consuming/ConsumingourRESTservice andSOAPservice,selectingbetween/ChoosingbetweenSOAPandREST services retrieveAllSeatTypesmethod/Addingproducerclasses RFC6455 URL/AnoverviewofWebSockets RichFaces URL/Combiningtheschedulerintoourapplication installing/InstallingRichFaces implementing/Makingyourapplicationrich Role-basedsecurity about/Role-basedsecurity administrativeoperations,auditing/Auditingadministrativeoperations RoleBasedAccessControl(RBAC)/NewfeaturesinWildFly rootfolder,JBOSS_HOME bin/TheWildFly8directorylayout bin/client/TheWildFly8directorylayout bin/init.d/TheWildFly8directorylayout bin/service/TheWildFly8directorylayout docs/examples/TheWildFly8directorylayout docs/schema/TheWildFly8directorylayout domain/TheWildFly8directorylayout modules/TheWildFly8directorylayout standalone/TheWildFly8directorylayout appclient/TheWildFly8directorylayout welcome-content/TheWildFly8directorylayout run()method/CodingtheEJBclient runninginstance patching/Patchingarunninginstance Runtimetab/Launchingthewebconsole S @Scheduleannotation/Schedulingtimerevents @SessionScopedscope/CDIscopes samplecontent,ofXMLfile URL/WildFlyCDIimplementation SASL_POLICY_NOANONYMOUSoption/ConnectingtoanSSL-awaresecurity realm ScanIntervalattribute/Changingthedeploymentscannerproperties scheduler combining,intoapplication/Combiningtheschedulerintoourapplication scheduler,intoapplication RichFaces,installing/InstallingRichFaces RichFaces,implementing/Makingyourapplicationrich application,running/Runningtheapplication interceptors,creating/Creatinginterceptors scopes,CDI @RequestScoped/CDIscopes @ConversationScoped/CDIscopes @SessionScoped/CDIscopes @ApplicationScoped/CDIscopes @Dependent/CDIscopes scriptinglanguages used,forwrappingCLIexecution/UsingscriptinglanguagestowrapCLI execution Seam3project URL/WildFlyCDIimplementation SeatTypeobject/Addingacontrollertodriveuserrequests SecureSocketLayer enabling,onWildFly/EnablingtheSecureSocketLayeronWildFly SecureSocketLayer,onWildFly certificatemanagementtools/Certificatemanagementtools HTTPcommunication,securingwithself-signedcertificate/SecuringtheHTTP communicationwithaself-signedcertificate servercertificate,generating/Generatingtheserverandclientcertificates clientcertificate,generating/Generatingtheserverandclientcertificates SSL-awaresecurityrealm,creating/CreatinganSSL-awaresecurityrealm HTTPcommunication,securingwithcertificatesignedbyCA/SecuringHTTP communicationwithacertificatesignedbyaCA EJBcommunication,securing/SecuringEJBcommunication SSL-awaresecurityrealm,connectingto/ConnectingtoanSSL-awaresecurity realm self-signedcertificate HTTPcommunication,securingwith/SecuringtheHTTPcommunicationwith aself-signedcertificate sendmethod/Expandingourclientapplication sendTextmethod/TransformingPOJOstoJSON serialization/ProgrammingconsiderationstoachieveHA Server-SentEvents(SSE) about/AnalternativetoWebSockets servercertificate generating/Generatingtheserverandclientcertificates servercomponents installing/Installingtheserverandclientcomponents JavaSE,installing/InstallingJavaSE Eclipseenvironment,installing/InstallingtheEclipseenvironment developmentenvironments/Alternativedevelopmentenvironments Maven,installing/InstallingMaven serverendpointlistener/AbrieflookattheJAXWSarchitecture servergroups deployingto/Deployingtoallservergroups servers data/TheWildFly8directorylayout log/TheWildFly8directorylayout tmp/TheWildFly8directorylayout restarting,indomain/Restartingserversinadomain ServiceEndpointInterface(SEI)/EJB3StatelessSessionBean(SLSB)webservices services adding,toapplication/Addingservicestoyourapplication session/ThebuildingblocksofJMS sessionbeans about/EJB3.2–anoverview Statelesssessionbeans(SLSB)/EJB3.2–anoverview Statefulsessionbeans(SFSB)/EJB3.2–anoverview singletonEJB/EJB3.2–anoverview localbusinessinterface/EJB3.2–anoverview remotebusinessinterface/EJB3.2–anoverview No-interfaceview/EJB3.2–anoverview cooking/Cookingsessionbeans Sessionparameter/Creatingourfirstendpoint shellcommand/LaunchingtheCLI ShinkWrapResolver URL/ShrinkWrapResolver ShrinkWrap URL/WritingyourfirstArquilliantest ShrinkWrapDescriptors/ShrinkWrapDescriptors ShrinkWrapResolver/ShrinkWrapResolver SimpleAuthenticationandSecurityLayer(SASL)/ConnectingtoanSSL-aware securityrealm singleservergroup deployingto/Deployingtoasingleservergroup singletonEJB/EJB3.2–anoverview singletonEJBs developing/DevelopingsingletonEJBs EJBmodule/DevelopingsingletonEJBs webmodule/DevelopingsingletonEJBs resourceadaptermodule/DevelopingsingletonEJBs Enterprisearchive/DevelopingsingletonEJBs EJBprojectobjectmodule(pom.xml),configuring/ConfiguringtheEJB projectobjectmodule(pom.xml) EJBapplication,coding/CodingourEJBapplication beanconcurrency,controlling/Controllingbeanconcurrency sessionbeans,cooking/Cookingsessionbeans statelessbean,adding/Addingastatelessbean statefulbean,adding/Addingastatefulbean SOAP-basedwebservices developing/DevelopingSOAP-basedwebservices building,strategies/StrategiestobuildSOAP-basedwebservices JBossSOAP-basedwebservicesstack/JBossSOAP-basedwebservicesstack JAXWSarchitecture/AbrieflookattheJAXWSarchitecture coding,withWildFly/CodingSOAPwebserviceswithWildFly SOAPservice andRESTservice,selectingbetween/ChoosingbetweenSOAPandREST services SoapUI about/Testingoursimplewebservice SOAPwebservices,approaches top-downapproach/StrategiestobuildSOAP-basedwebservices bottom-upapproach/StrategiestobuildSOAP-basedwebservices SOAPwebservices,withWildFly POJOwebservice,developing/DevelopingaPOJOwebservice inspecting,fromconsole/Inspectingthewebservicefromtheconsole testing/Testingoursimplewebservice EJB3StatelessSessionBean(SLSB)webservices/EJB3StatelessSession Bean(SLSB)webservices webserviceconsumer,developing/Developingawebserviceconsumer Spock used,forrunningArquilliantests/RunningArquilliantestsusingSpock about/RunningArquilliantestsusingSpock URL/RunningArquilliantestsusingSpock srcfolder,Arquillian main/java//GettingstartedwithArquillian main/resources//GettingstartedwithArquillian test/java//GettingstartedwithArquillian test/resources//GettingstartedwithArquillian SSL-awaresecurityrealm creating/CreatinganSSL-awaresecurityrealm connectingto/ConnectingtoanSSL-awaresecurityrealm SSL_ENABLEDoption/ConnectingtoanSSL-awaresecurityrealm standalonecluster/WildFlyclustering standalonemodetree configuration/TheWildFly8directorylayout data/TheWildFly8directorylayout deployments/TheWildFly8directorylayout lib/ext/TheWildFly8directorylayout log/TheWildFly8directorylayout tmp/TheWildFly8directorylayout STARTTLSoption/ConnectingtoanSSL-awaresecurityrealm statefulbean adding/Addingastatefulbean StatefulSessionBean(SFSB)/CreatingHAStatefulSessionBeans Statefulsessionbeans(SFSB)/EJB3.2–anoverview statelessbean adding/Addingastatelessbean StatelessSessionBean(SLSB)/Deployingclusteredapplications Statelesssessionbeans(SLSB)/EJB3.2–anoverview stereotypes/Creatingthebeans stickywebsessions/AchievingHAinJSFapplications Stringparameter/Creatingourfirstendpoint subscription durable/AshortintroductiontoJMS nondurable/AshortintroductiontoJMS symmetricencryption/Securingthetransportlayer synchronously/AshortintroductiontoJMS T @Transactionalannotation/AreEJBsandJSFManagedBeansobsolete? tabcompletionhelper using/Usingthetabcompletionhelper Tasksteps/Theoverviewofthebatchingframework testing instruments,usedfor/Instrumentsusedfortesting testtypes about/Testtypes instruments,usedfortesting/Instrumentsusedfortesting thenconstruction/RunningArquilliantestsusingSpock threads introducing,toenterprisebeans/Introducingthreadstoenterprisebeans ticketexample REST,addingto/AddingRESTtoourticketexample compiling/Compilingourticketexample ticketingsystem rethinking/Rethinkingyourticketingsystem requireddependencies,adding/Addingtherequireddependencies Ticketwebapplication loginmodule,using/UsingtheloginmoduleintheTicketwebapplication timeoutmethod/Programmatictimercreation timer creating/Programmatictimercreation timerevents scheduling/Schedulingtimerevents top-downapproach/StrategiestobuildSOAP-basedwebservices transactionmode/Transactionandacknowledgmentmodes transportlayer securing/Securingthetransportlayer SecureSocketLayer,enablingonWildFly/EnablingtheSecureSocketLayer onWildFly transportlayersecurity URL/Securingthetransportlayer TunneledTransportLayerSecurity(TTLS)/ConnectingtoanSSL-awaresecurity realm Tyrus URL/TransformingPOJOstoJSON about/WebSocketstesting U ui$compositionelement about/Buildingtheview undeploycommand/Deployingapplicationsusingthecommand-lineinterface, Deployingtoallservergroups unittests/Testtypes userauthentication adding/Addinguserauthentication userrequests driving,viacontrolleraddition/Addingacontrollertodriveuserrequests V view building/Buildingtheview JSF2facetsuggestions/JSF2facetsuggestions viewscope about/AreEJBsandJSFManagedBeansobsolete? Vim,withpython-mode URL/UsingscriptinglanguagestowrapCLIexecution W @WebMethodattribute/DevelopingaPOJOwebservice @WebParamannotation/DevelopingaPOJOwebservice @WebResultannotation/DevelopingaPOJOwebservice webapplication loadbalancing/Loadbalancingyourwebapplications webapplication,clustering about/Webapplicationclustering,Clusteringyourwebapplications programmingconsiderations,forachievingHA/Programmingconsiderationsto achieveHA HA,achievinginJSFapplications/AchievingHAinJSFapplications webapplication,loadbalancing about/Loadbalancingyourwebapplications mod_cluster,installing/Installingmod_cluster webconsole launching/Launchingthewebconsole Configurationtab/Launchingthewebconsole Runtimetab/Launchingthewebconsole Administrationtab/Launchingthewebconsole deployments,managingwith/Managingdeploymentswiththewebconsole deploymentscannerproperties,changing/Changingthedeploymentscanner properties WebDriver about/Additionalinformation webinterface WildFly8,managingwith/ManagingWildFly8withthewebinterface WebJars URL/CodingtheJSFview webmodule/DevelopingsingletonEJBs webserviceconsumer developing/Developingawebserviceconsumer webservices securing/Securingwebservices WebSockets overview/AnoverviewofWebSockets advantages/AnoverviewofWebSockets working/HowdoWebSocketswork alternativeto/AnalternativetoWebSockets testing/WebSocketstesting whenconstruction/RunningArquilliantestsusingSpock WildFly overview/AnoverviewofJavaEEandWildFly using,withEAP/WildFlyandEnterpriseApplicationPlatform features/NewfeaturesinWildFly URL/InstallingWildFly,ClusteringtheTicketexample installing/InstallingWildFly initializing/StartingWildFly terminating/StoppingWildFly shutdownscript,locating/Locatingtheshutdownscript terminating,onremotemachine/StoppingWildFlyonaremotemachine restarting/RestartingWildFly JDBCdriver,installingin/InstallingtheJDBCdriverinWildFly SOAPwebservices,codingwith/CodingSOAPwebserviceswithWildFly accesscontrolstrategies/Role-basedsecurity SecureSocketLayer,enablingon/EnablingtheSecureSocketLayeron WildFly WildFly8 coreconcepts/WildFly8coreconcepts advantages/WildFly8coreconcepts directorylayout/TheWildFly8directorylayout managing,withwebinterface/ManagingWildFly8withthewebinterface firstapplication,deployingto/DeployingyourfirstapplicationtoWildFly8 advancedEclipsedeployment,options/AdvancedEclipsedeploymentoptions applicationsdeploying,command-lineinterfaceused/Deployingapplications usingthecommand-lineinterface WildFlybuilt-inmemoryH2database URL/Configuringpersistence WildFlyCDIimplementation/WildFlyCDIimplementation WildFlyCLI about/EnteringtheWildFlyCLI launching/LaunchingtheCLI remotehosts,connectingfrom/Connectingfromremotehosts used,ingraphicalmode/UsingaCLIinthegraphicalmode CLIcommands,constructing/ConstructingCLIcommands used,fordeployingapplications/DeployingapplicationsusingtheCLI CLIscripts,creating/CreatingCLIscripts WildFlyclustering about/WildFlyclustering standalonenodescluster,initiating/Startingaclusterofstandalonenodes domainnodescluster,initiating/Startingaclusterofdomainnodes WildFlydocumentation URL/Auditingadministrativeoperations,TheWildFlysecuritysubsystem WildFlydomain applications,deployingto/DeployingapplicationstoaWildFlydomain WildFlymodules categories/WildFlyCDIimplementation WildFlynodes application,deployingto/DeployinganapplicationtoseveralWildFlynodes WildFlysecuritysubsystem/TheWildFlysecuritysubsystem WSDL URL/DevelopingSOAP-basedwebservices TableofContents JavaEE7DevelopmentwithWildFly Credits AbouttheAuthors AbouttheReviewers www.PacktPub.com Supportfiles,eBooks,discountoffers,andmore Whysubscribe? FreeaccessforPacktaccountholders InstantupdatesonnewPacktbooks Preface Whatthisbookcovers Whatyouneedforthisbook Whothisbookisfor Conventions Readerfeedback Customersupport Downloadingtheexamplecode Errata Piracy Questions 1.GettingStartedwithWildFly AnoverviewofJavaEEandWildFly WildFlyandEnterpriseApplicationPlatform WelcometoJavaEE7 JavaServerFaces2.2–JSR344 EnterpriseJavaBeans3.2–JSR345 JavaPersistenceAPI2.1–JSR338 ContextsandDependencyInjectionforJavaEE1.1–JSR346 JavaServletAPI3.1–JSR340 JAX-RS,theJavaAPIforRESTfulWebServices2.0–JSR339 JavaMessageService2.0–JSR343 BeanValidation1.1–JSR349 ConcurrencyutilitiesforJavaEE1.0–JSR236 BatchapplicationsfortheJavaPlatform1.0–JSR352 JavaAPIforJSONProcessing1.0–JSR353 JavaAPIforWebSocket1.0–JSR356 NewfeaturesinWildFly Installingtheserverandclientcomponents InstallingJavaSE Testingtheinstallation InstallingWildFly StartingWildFly Connectingtotheserverwiththecommand-lineinterface StoppingWildFly Locatingtheshutdownscript StoppingWildFlyonaremotemachine RestartingWildFly InstallingtheEclipseenvironment InstallingJBossTools Alternativedevelopmentenvironments InstallingMaven Testingtheinstallation Summary 2.YourFirstJavaEEApplicationonWildFly WildFly8coreconcepts TheWildFly8directorylayout Managingtheapplicationserver ManagingWildFly8withthewebinterface Launchingthewebconsole DeployingyourfirstapplicationtoWildFly8 AdvancedEclipsedeploymentoptions Managingdeploymentswiththewebconsole Changingthedeploymentscannerproperties Deployingapplicationsusingthecommand-lineinterface Deployingapplicationstoadomain Summary 3.IntroducingJavaEE7–EJBs EJB3.2–anoverview DevelopingsingletonEJBs ConfiguringtheEJBprojectobjectmodule(pom.xml) CodingourEJBapplication Controllingbeanconcurrency Usingbean-managedconcurrency Cookingsessionbeans Addingastatelessbean Addingastatefulbean DeployingtheEJBapplication CreatingaremoteEJBclient Configuringtheclient’sprojectobjectmodule CodingtheEJBclient AddingtheEJBclientconfiguration Runningtheclientapplication Addinguserauthentication UsingtheEJBtimerservice Programmatictimercreation Schedulingtimerevents AddingasynchronousmethodstoourEJBs Usingfire-and-forgetasynchronouscalls ReturningaFutureobjecttotheclient Summary 4.LearningContextandDependencyInjection IntroducingContextsandDependencyInjection Namedbeans CDIscopes WildFlyCDIimplementation Rethinkingyourticketingsystem Addingtherequireddependencies Creatingthebeans Buildingtheview JSF2facetsuggestions Gettingreadytoruntheapplication Combiningtheschedulerintoourapplication InstallingRichFaces Makingyourapplicationrich Runningtheapplication Creatinginterceptors AreEJBsandJSFManagedBeansobsolete? Summary 5.CombiningPersistencewithCDI Datapersistencemeetsthestandard WorkingwithJPA Addingpersistencetoourapplication Settingupthedatabase InstallingtheJDBCdriverinWildFly Usingthecommand-lineinterfacetocreateanewdatasource CreatingtheMavenproject AddingtheMavenconfiguration Cookingentities AddingBeanValidation Configuringpersistence Addingproducerclasses Codingqueriesforyourapplication Addingservicestoyourapplication Addingacontrollertodriveuserrequests CodingtheJSFview Runningtheexample Summary 6.DevelopingApplicationswithJBossJMSProvider AshortintroductiontoJMS ThebuildingblocksofJMS TheJBossmessagingsubsystem Creatingandusingconnectionfactories UsingJMSdestinations Addingmessage-drivenbeanstoyourapplication Cookingmessage-drivenbeans AddingtheJMSproducer Compilinganddeployingtheapplication Specifyingwhichmessagetoreceiveusingselectors Transactionandacknowledgmentmodes UsingJMStointegratewithexternalsystems Areal-worldexample–HornetQandActiveMQintegration InstallingtheActiveMQresourceadapter ConsumingActiveMQmessages Summary 7.AddingWebServicestoYourApplications DevelopingSOAP-basedwebservices StrategiestobuildSOAP-basedwebservices JBossSOAP-basedwebservicesstack AbrieflookattheJAXWSarchitecture CodingSOAPwebserviceswithWildFly DevelopingaPOJOwebservice Inspectingthewebservicefromtheconsole Testingoursimplewebservice EJB3StatelessSessionBean(SLSB)webservices Developingawebserviceconsumer DevelopingREST-basedwebservices AccessingRESTresources JBossRESTwebservices ActivatingJAX-RS AddingRESTtoourticketexample Addingfilters ConsumingourRESTservice Compilingourticketexample AddingAngularJS ChoosingbetweenSOAPandRESTservices Summary 8.AddingWebSockets AnoverviewofWebSockets HowdoWebSocketswork Creatingourfirstendpoint Expandingourclientapplication TransformingPOJOstoJSON AnalternativetoWebSockets Summary 9.ManagingtheApplicationServer EnteringtheWildFlyCLI LaunchingtheCLI Connectingfromremotehosts UsingaCLIinthegraphicalmode ConstructingCLIcommands Determiningtheresourceaddress Performingoperationsonresources Usingthetabcompletionhelper DeployingapplicationsusingtheCLI DeployingapplicationstoaWildFlydomain Deployingtoallservergroups Deployingtoasingleservergroup CreatingCLIscripts DeployinganapplicationtoseveralWildFlynodes Restartingserversinadomain Installingadatasourceasamodule AddingJMSresources UsingadvancedlanguagestocreatepowerfulCLIscripts UsingscriptinglanguagestowrapCLIexecution UsingtherawmanagementAPItomanagetheapplicationserver ReadingmanagementmodeldescriptionsviatherawmanagementAPI CreatingyourresourcewatchesusingthedetypedAPI Role-basedsecurity Auditingadministrativeoperations Patchingarunninginstance Summary 10.SecuringWildFlyApplications ApproachingtheJavasecurityAPI TheWildFlysecuritysubsystem Settingupyourfirstloginmodule UsingtheloginmoduleintheTicketwebapplication SwitchingtoFORM-basedsecurity CreatingaDatabaseloginmodule Encryptingpasswords UsingtheDatabaseloginmoduleinyourapplication SecuringEJBs Securingwebservices Securingthetransportlayer EnablingtheSecureSocketLayeronWildFly Certificatemanagementtools SecuringtheHTTPcommunicationwithaself-signedcertificate Generatingtheserverandclientcertificates CreatinganSSL-awaresecurityrealm SecuringHTTPcommunicationwithacertificatesignedbyaCA SecuringEJBcommunication ConnectingtoanSSL-awaresecurityrealm Summary 11.ClusteringWildFlyApplications Clusteringbasics WildFlyclustering Startingaclusterofstandalonenodes Startingaclusterofdomainnodes Thedomaincontrollerconfiguration Hostconfigurations Deployingclusteredapplications CreatingHAStatefulSessionBeans ClusteringtheTicketexample Turningyourcacheintoadistributedcache Codingthecluster-awareremoteclient Deployingandtestinghighavailability Webapplicationclustering Loadbalancingyourwebapplications Installingmod_cluster Clusteringyourwebapplications ProgrammingconsiderationstoachieveHA AchievingHAinJSFapplications Summary 12.Long-termTasks’Execution Theoverviewofthebatchingframework Ourfirstbatchjob Creatingachunk-basedbatchstep Creatingajob-basedbatchstep UsingconcurrencyutilitiesinJavaEE Introducingthreadstoenterprisebeans Summary 13.TestingYourApplications Testtypes Instrumentsusedfortesting GettingstartedwithArquillian WritinganArquilliantest Configuringthepom.xmlfile WritingyourfirstArquilliantest RunningArquillianTicketTest RunningArquilliantestsusingSpock ShrinkWrapResolver ShrinkWrapDescriptors Persistencetesting ArquillianWarp WebSocketstesting EnhancingyourArquilliantest Additionalinformation Summary A.RapidDevelopmentUsingJBossForge InstallingForge StartingForge CreatingyourfirstJavaEE7applicationwithJBossForge Buildinganddeployingtheapplication YourForge-demoapplicationinaction Index