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”>&copy;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”>&copy;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