o'reilly : java servlet and jsp cookbookdl.booktolearn.com/ebooks2/computer/programming/... ·...
TRANSCRIPT
• TableofContents• Index• Reviews• ReaderReviews• Errata• Academic
JavaServlet&JSPCookbookByBruceW.Perry
Publisher :O'ReillyPubDate :January2004
ISBN :0-596-00572-5Pages :746
Withliterallyhundredsofexamplesandthousandsoflinesofcode,theJavaServletandJSPCookbookyieldstipsandtechniquesthatanyJavawebdeveloperwhousesJavaServerPagesorservletswilluseeveryday,alongwithfull-fledgedsolutionstosignificantwebapplicationdevelopmentproblemsthatdeveloperscaninsertdirectlyinto
theirownapplications.
• TableofContents• Index• Reviews• ReaderReviews• Errata• Academic
JavaServlet&JSPCookbookByBruceW.Perry
Publisher :O'ReillyPubDate :January2004
ISBN :0-596-00572-5Pages :746
Copyright Preface What'sintheBook
Audience
Organization
ConventionsUsedinThisBook
UsingCodeExamples
CommentsandQuestions
Acknowledgments
Chapter1.WritingServletsandJSPs Introduction
Recipe1.1.WritingaServlet
Recipe1.2.WritingaJSP
Recipe1.3.CompilingaServlet
Recipe1.4.PackagingServletsandJSPs
Recipe1.5.CreatingtheDeploymentDescriptor
Chapter2.DeployingServletsandJSPs Introduction
Recipe2.1.DeployinganIndividualServletonTomcat
Recipe2.2.UsingaContextElementinTomcat'sserver.xml
Recipe2.3.DeployinganIndividualServletonWebLogic
Recipe2.4.DeployinganIndividualJSPonTomcat
Recipe2.5.DeployinganIndividualJSPonWebLogic
Recipe2.6.DeployingaWebApplicationonTomcat
Recipe2.7.DeployingaWebApplicationonWebLogicUsingAnt
Recipe2.8.UsingtheWebLogicAdministrationConsole
Recipe2.9.UsingWebLogicBuildertoDeployaWebApplication
Recipe2.10.Usingtheweblogic.DeployerCommand-LineTool
Chapter3.NamingYourServlets Introduction
Recipe3.1.MappingaServlettoaNameinweb.xml
Recipe3.2.CreatingMoreThanOneMappingtoaServlet
Recipe3.3.CreatingaJSP-TypeURLforaServlet
Recipe3.4.MappingStaticContenttoaServlet
Recipe3.5.InvokingaServletWithoutaweb.xmlMapping
Recipe3.6.MappingAllRequestsWithinaWebApplicationtoaServlet
Recipe3.7.MappingRequeststoaControllerandPreservingServletMappings
Recipe3.8.CreatingWelcomeFilesforaWebApplication
Recipe3.9.RestrictingRequestsforCertainServlets
Recipe3.10.GivingOnlytheControllerAccesstoCertainServlets
Chapter4.UsingApacheAnt Introduction
Recipe4.1.ObtainingandSettingUpAnt
Recipe4.2.UsingAntTargets
Recipe4.3.IncludingTomcatJARfilesintheBuildFileClasspath
Recipe4.4.CompilingaServletwithanAntBuildFile
Recipe4.5.CreatingaWARFilewithAnt
Recipe4.6.CreatingaJARFilewithAnt
Recipe4.7.StartingaTomcatApplicationwithAnt
Recipe4.8.StoppingaTomcatApplicationwithAnt
Chapter5.AlteringtheFormatofJSPs
Introduction
Recipe5.1.PrecompilingaJSPinTomcat
Recipe5.2.PrecompilingaJSPinWebLogic
Recipe5.3.PrecompilingJSPswiththePrecompilationProtocol
Recipe5.4.MappingaJSPtoItsPageImplementationClass
Recipe5.5.CreatingaJSPfromScratchasaJSPDocument
Recipe5.6.GeneratinganXMLViewfromaJSP
Chapter6.DynamicallyIncludingContentinServletsandJSPs Introduction
Recipe6.1.IncludingaResourceEachTimeaServletHandlesaRequest
Recipe6.2.UsinganExternalConfigurationtoIncludeaResourceinaServlet
Recipe6.3.IncludingResourcesNestedatMultipleLevelsinaServlet
Recipe6.4.IncludingaResourcethatSeldomChangesintoaJSP
Recipe6.5.IncludingContentinaJSPEachTimetheJSPHandlesaRequest
Recipe6.6.UsinganExternalConfigurationFiletoIncludeaResourceinaJSP
Recipe6.7.IncludinganXMLFragmentinaJSPDocument
Recipe6.8.IncludingContentfromOutsideaContextinaJSP
Chapter7.HandlingWebFormDatainServletsandJSPs Introduction
Recipe7.1.HandlingaPOSTHTTPRequestinaServlet
Recipe7.2.HandlingaPOSTHTTPRequestinaJSP
Recipe7.3.SettingthePropertiesofaJavaBeaninaJSP
Recipe7.4.SettingaScopedAttributeinaJSPtotheValueofaFormParameter
Recipe7.5.PostingDatafromaServlet
Recipe7.6.PostingDatafromaJSP
Recipe7.7.UsingaServlettoAddaParametertoaQueryString
Recipe7.8.UsingaJSPtoAddaParametertoaQueryString
Recipe7.9.UsingaFiltertoReadParameterValues
Chapter8.UploadingFiles Introduction
Recipe8.1.PreparingtheHTMLPageforFileUploads
Recipe8.2.Usingthecom.oreilly.servletLibrary
Recipe8.3.UploadingOneFileataTime
Recipe8.4.UploadingMultipleFiles
Recipe8.5.RenamingFiles
Recipe8.6.UsingaJSPtoHandleaFileUpload
Chapter9.HandlingExceptionsinWebApplications
Introduction
Recipe9.1.DeclaringExceptionHandlersinweb.xml
Recipe9.2.CreatinganException-HandlingServlet
Recipe9.3.SendinganErrorfromaServlet
Recipe9.4.SendinganErrorfromaJSP
Recipe9.5.CreatinganError-HandlingJSP
Recipe9.6.DeclaringaSpecialException-HandlingJSPforOtherJSPs
Chapter10.ReadingandSettingCookies Introduction
Recipe10.1.SettingaCookiewithaServlet
Recipe10.2.CreatinganArrayfromAlloftheRequest'sCookies
Recipe10.3.SettingaCookiewithaJSP
Recipe10.4.ReadingCookieValueswithaServlet
Recipe10.5.ReadingCookieValueswithaJSP
Recipe10.6.AlteringorRemovingaCookieThatHasAlreadyBeenSet
Chapter11.SessionTracking Introduction
Recipe11.1.SettingtheSessionTimeoutinweb.xml
Recipe11.2.SettingtheSessionTimeoutinAllTomcatWebApplications
Recipe11.3.SettingtheSessionTimeoutProgrammatically
Recipe11.4.CheckingifaSessionExistsinanHttpServletRequest
Recipe11.5.TrackingSessionActivityinServlets
Recipe11.6.TrackingSessionActivityinJSPs
Recipe11.7.UsingURLRewritinginaJSP
Recipe11.8.UsingURLRewritinginaServlet
Recipe11.9.UsingaListenertoTracktheSessionLifecycle
Recipe11.10.UsingaListenertoMonitorSessionAttributes
Recipe11.11.UsingaFiltertoMonitorSessionAttributes
Chapter12.IntegratingJavaScriptwithServletsandJSPs Introduction
Recipe12.1.IncludingJavaScriptModulesinaServlet
Recipe12.2.IncludingJavaScriptModulesinaJSP
Recipe12.3.CreatingaNewWindowwithJavaScriptinaServlet
Recipe12.4.CreatingaNewWindowwithJavaScriptinaJSP
Recipe12.5.UsingJavaScripttoValidateFormValuesinaServlet
Recipe12.6.UsingJavaScripttoValidateFormValuesinaJSP
Chapter13.SendingNon-HTMLContent Introduction
Recipe13.1.SendingaPDFFile
Recipe13.2.SendingaWordProcessingFile
Recipe13.3.SendinganXMLfile
Recipe13.4.SendinganAudioFile
Recipe13.5.ViewingInternalResourcesinaServlet
Chapter14.LoggingMessagesfromServletsandJSPs Introduction
Recipe14.1.LoggingWithoutLog4j
Recipe14.2.SettingUpLog4j
Recipe14.3.UsingaLoggerWithoutaConfigurationFile
Recipe14.4.AddinganAppendertotheRootLogger
Recipe14.5.UsingaPatternwithaLogger'sAppender
Recipe14.6.Usinglog4jinaJSP
Recipe14.7.LoggingMessagesUsingaServletContextEventListener
Recipe14.8.LoggingMessagesUsingaSessionEventListener
Chapter15.AuthenticatingClients Introduction
Recipe15.1.CreatingUsersandPasswordswithTomcat
Recipe15.2.SettingUpSSLonTomcat
Recipe15.3.UsingBASICAuthentication
Recipe15.4.UsingForm-BasedAuthentication
Recipe15.5.LoggingOutaUser
Recipe15.6.UsingJAAStoCreateaLoginModule
Recipe15.7.CreatingtheJAASConfigurationFile
Recipe15.8.UsingJAASinaServlet
Recipe15.9.UsingJAASinaJSP
Chapter16.Binding,Accessing,andRemovingAttributesinWebApplications Introduction
Recipe16.1.SettingServletContextAttributesinServlets
Recipe16.2.SettingServletContextAttributesinJSPs
Recipe16.3.AccessingorRemovingServletContextAttributesinServlets
Recipe16.4.AccessingorRemovingServletContextAttributesinJSPs
Recipe16.5.SettingSessionAttributesinServlets
Recipe16.6.SettingSessionAttributesinJSPs
Recipe16.7.AccessingorRemovingSessionAttributesinServlets
Recipe16.8.AccessingorRemovingSessionAttributesinJSPs
Recipe16.9.SettingRequestAttributesinServlets
Recipe16.10.SettingRequestAttributesinJSPs
Recipe16.11.AccessingorRemovingRequestAttributesinServlets
Recipe16.12.AccessingorRemovingRequestAttributesinJSPs
Chapter17.EmbeddingMultimediainJSPs Introduction
Recipe17.1.EmbeddinganAppletinaJSPUsingjsp:plugin
Recipe17.2.EmbeddinganAppletinaJSPUsingtheHTMLConverter
Recipe17.3.AutomaticallyCreatingHTMLTemplateforIncludingFlashFiles
Recipe17.4.WritingHTMLTemplatetoEmbedaFlashFile
Recipe17.5.EmbeddingFlashinaServlet
Recipe17.6.EmbeddingaQuickTimeMovieinaJSP
Recipe17.7.EmbeddinganSVGFileinaJSP
Recipe17.8.EmbeddingaBackgroundSoundtrackinaJSP
Chapter18.WorkingWiththeClientRequest Introduction
Recipe18.1.ExaminingHTTPRequestHeadersinaServlet
Recipe18.2.ExaminingHTTPRequestHeadersinaJSP
Recipe18.3.UsingaFiltertoAlterRequestHeaders
Recipe18.4.AutomaticallyRefreshingaServlet
Recipe18.5.AutomaticallyRefreshingaJSP
Recipe18.6.CountingtheNumberofWebApplicationRequests
Chapter19.FilteringRequestsandResponses Introduction
Recipe19.1.MappingaFiltertoaServlet
Recipe19.2.MappingaFiltertoaJSP
Recipe19.3.MappingMoreThanOneFiltertoaServlet
Recipe19.4.ChangingtheOrderinWhichFiltersareAppliedtoServlets
Recipe19.5.ConfiguringInitializationParametersforaFilter
Recipe19.6.OptionallyBlockingaRequestwithaFilter
Recipe19.7.FilteringtheHTTPResponse
Recipe19.8.UsingFilterswithRequestDispatcherObjects
Recipe19.9.CheckingFormParameterswithaFilter
Recipe19.10.BlockingIPAddresseswithaFilter
Chapter20.ManagingEmailinServletsandJSPs Introduction
Recipe20.1.PlacingtheEmail-RelatedClassesonyourClasspath
Recipe20.2.SendingEmailfromaServlet
Recipe20.3.SendingEmailfromaServletUsingaJavaBean
Recipe20.4.AccessingEmailfromaServlet
Recipe20.5.AccessingEmailfromaServletUsingaJavaBean
Recipe20.6.HandlingAttachmentsfromanEmailReceivedinaServlet
Recipe20.7.AddingAttachmentstoanEmailinaServlet
Recipe20.8.ReadingaReceivedEmail'sHeadersfromaServlet
Chapter21.AccessingDatabases Introduction
Recipe21.1.AccessingaDatabasefromaServletWithoutDataSource
Recipe21.2.ConfiguringaDataSourceinTomcat
Recipe21.3.UsingaDataSourceinaServletwithTomcat
Recipe21.4.CreatingaDataSourceonWebLogic
Recipe21.5.UsingaJNDILookuptogetaDataSourcefromWebLogic
Recipe21.6.UsingaDataSourcefromWebLogicinaJSP
Recipe21.7.CallingaStoredProcedurefromaServlet
Recipe21.8.CallingaStoredProcedurefromaJSP
Recipe21.9.ConvertingaResultSettoaResultObject
Recipe21.10.ExecutingSeveralSQLStatementsWithinaSingleTransaction
Recipe21.11.UsingTransactionswithJSPs
Recipe21.12.FindingInformationaboutaResultSet
Chapter22.UsingCustomTagLibraries Introduction
Recipe22.1.CreatingaClassicTagHandler
Recipe22.2.CreatingaJSP1.2TLDforaClassicTagHandler
Recipe22.3.CreatingaJSP2.0TLDforaClassicTagHandler
Recipe22.4.PackagingaTagLibraryinaWebApplication
Recipe22.5.PackagingtheTagLibraryinaJARFile
Recipe22.6.UsingtheCustomTaginaJSP
Recipe22.7.HandlingExceptionsinaCustomTagClass
Recipe22.8.CreatingaSimpleTagHandler
Recipe22.9.CreatingaTLDforaSimpleTagHandler
Recipe22.10.UsingaSimpleTagHandlerinaJSP
Recipe22.11.CreatingaJSPTagFile
Recipe22.12.PackagingtheJSPTagFileinaWebApplication
Recipe22.13.PackagingtheJSPTagFileinaJAR
Recipe22.14.UsingaCustomTagAssociatedwithaTagFile
Recipe22.15.AddingaListenerClasstoaTagLibrary
Chapter23.UsingtheJSTL Introduction
Recipe23.1.DownloadingtheJSTL1.0andUsingtheJSTLTagsinJSPs
Recipe23.2.DownloadingtheJavaWebServicesDeveloperPack
Recipe23.3.UsingtheCoreJSTLTags
Recipe23.4.UsingtheXMLCoreJSTLTags
Recipe23.5.UsingtheXMLTransformTags
Recipe23.6.UsingtheFormattingJSTLTags
Recipe23.7.UsingASQLJSTLTagwithaDataSourceConfiguration
Recipe23.8.UsingASQLJSTLTagWithoutaDataSourceConfiguration
Recipe23.9.AccessingScopedVariableswiththeEL
Recipe23.10.AccessingRequestParameterswiththeEL
Recipe23.11.UsingtheELtoAccessRequestHeaders
Recipe23.12.UsingtheELtoAccessOneRequestHeader
Recipe23.13.AccessingCookieswiththeEL
Recipe23.14.UsingtheELtoAccessJavaBeanProperties
Recipe23.15.UsingJSTLFunctions
Chapter24.Internationalization Introduction
Recipe24.1.DetectingtheClientLocaleinaServlet
Recipe24.2.DetectingtheClient'sLocalesinaJSP
Recipe24.3.CreatingaResourceBundleasaPropertiesFile
Recipe24.4.CreatingaResourceBundleasaJavaClass
Recipe24.5.UsingtheResourceBundleinaServlet
Recipe24.6.UsingtheResourceBundleinaJSP
Recipe24.7.FormattingDatesinaServlet
Recipe24.8.FormattingDatesinaJSP
Recipe24.9.FormattingCurrenciesinaServlet
Recipe24.10.FormattingCurrenciesinaJSP
Recipe24.11.FormattingPercentagesinaServlet
Recipe24.12.FormattingPercentagesinaJSP
Recipe24.13.SettingtheLocalizationContextintheDeploymentDescriptor
Chapter25.UsingJNDIandEnterpriseJavaBeans Introduction
Recipe25.1.ConfiguringaJNDIObjectinTomcat
Recipe25.2.AccessingtheTomcatJNDIResourcefromaServlet
Recipe25.3.AccessingtheTomcatJNDIResourcefromaJSP
Recipe25.4.ConfiguringaJNDIResourceinWebLogic
Recipe25.5.ViewingtheJNDITreeinWebLogic
Recipe25.6.AccessingtheWebLogicJNDIResourcefromaServlet
Recipe25.7.AccessingtheWebLogicJNDIResourcefromaJSP
Recipe25.8.AccessinganEJBUsingtheWebLogicJNDITree
Chapter26.HarvestingWebInformation Introduction
Recipe26.1.ParsinganHTMLPageUsingthejavax.swing.textSubpackages
Recipe26.2.UsingaServlettoHarvestWebData
Recipe26.3.CreatingaJavaBeanasaWebPageParser
Recipe26.4.UsingtheWebPageParsingJavaBeaninaServlet
Recipe26.5.UsingtheWebPageParsingJavaBeaninaJSP
Chapter27.UsingtheGoogleandAmazonWebAPIs Introduction
Recipe27.1.GettingSetUpwithGoogle'sWebAPI
Recipe27.2.CreatingaJavaBeantoConnectwithGoogle
Recipe27.3.UsingaServlettoConnectwithGoogle
Recipe27.4.UsingaJSPtoConnectwithGoogle
Recipe27.5.GettingSetUpwithAmazon'sWebServicesAPI
Recipe27.6.CreatingaJavaBeantoConnectwithAmazon
Recipe27.7.UsingaServlettoConnectwithAmazon
Recipe27.8.UsingaJSPtoConnectwithAmazon
Colophon Index
Copyright
Copyright©2004O'ReillyMedia,Inc.
PrintedintheUnitedStatesofAmerica.
PublishedbyO'ReillyMediaInc.,1005GravensteinHighwayNorth,Sebastopol,CA95472.
O'Reilly&Associatesbooksmaybepurchasedforeducational,business,orsalespromotionaluse.Onlineeditionsarealsoavailableformosttitles(http://safari.oreilly.com).Formoreinformation,contactourcorporate/institutionalsalesdepartment:(800)[email protected].
NutshellHandbook,theNutshellHandbooklogo,andtheO'ReillylogoareregisteredtrademarksofO'ReillyMedia,IncTheCookbookseriesdesignations,JavaServletandJSPCookbook,theimageofafennecfox,andrelatedtradedressaretrademarksofO'Reilly&Associates,Inc.
JavaandallJava-basedtrademarksandlogosaretrademarksorregisteredtrademarksofSunMicrosystems,Inc.,intheUnitedStatesandothercountries.O'ReillyMedia,Inc.isindependentofSunMicrosystems,Inc.
Manyofthedesignationsusedbymanufacturersandsellerstodistinguishtheirproductsareclaimedastrademarks.Wherethosedesignationsappearinthisbook,andO'Reilly&Associateswasawareofatrademarkclaim,thedesignationshavebeenprintedincapsorinitialcaps.
Whileeveryprecautionhasbeentakeninthepreparationofthisbook,thepublisherandauthorsassumenoresponsibilityforerrorsoromissions,orfordamagesresultingfromtheuseoftheinformationcontainedherein.
PrefaceOnahistoricaltimeline,thesagaofJavaasaserver-sideprogrammer'stoolofchoicebeganinearly1997whenSunMicrosystemsreleasedthe"Java™WebServer"betaandJavaServletDevelopersKit.[1]ServletsareatypeofJavaclassthatexecutesonaserver.Servletsdynamicallyhandlenetworkedrequestsandresponses,mostlyusingtheHypertextTransferProtocol(HTTP).InJune1999,SunintroducedJavaServerPages(JSPs),whichintermingledJavacodewithJavaScriptandHTMLtemplatetext.
[1]SeeSunMicrosystemsJavamilestonesandhistoryat:http://java.sun.com/features/2000/06/time-line.html.
JSPs,astheyarenowevolving(withJSPVersion2.0),aredesignedtoencapsulatedomainlogicinstandardandcustomtags,andseparatethisdomainlayerfromtheJSPcomponent'spresentationlogic.Thelatterconceptmeans"thestuffthatpeoplesee"whentheyinteractwithawebapplication,suchasHTML-relatedscreenwidgets.Ideally,aJSPusestagstointeractwithdatabasesandencapsulatedomainrules,andstaticordynamicallygeneratedtemplatetext,suchasXMLorXHTML,tocreatethevisualpagefortheuser.
Duringthelate1990s,Iwasafreelance,backendwebdeveloperusinganumberofdifferentlanguages.Whenserver-sideJavaappearedonthescene,Igreetedthenewswithasmuchreliefasjoy.Designedfromthebottomupasobject-orientedandmodular,Javarepresentedareassuringalternativetotheadhoc,ill-designed,albeitwell-intentionedmassesofweb-relatedcodeIwouldoftenencounterwhenanorganizationbroughtmeintothemidstofaproject.
Notonlycanyoueasilycreateyourownreusablecomponentsfor,say,sendingemailsimplybydesigninganduploadingtoyourwebapplicationoneormoreJavaclasses,[2]butyouhavetheentireJavaAPIatyourdisposalfordealingwithessential,low-levelitemssuchasString-
handling,fileI/O,andMathcalculations.Whatadeal!
[2]Forexample,theinstallationofabinaryActiveServerPages(ASP)componentoftenrequiredthescrutinyandpermissionofthehostingInternetServiceProvider(ISP),becauseabadlywrittenormaliciousASPcomponentcouldwreakhavocontheservermachine.
TheotherbigbenefitJavaprovidesisitscross-platformnature.Webdeveloperscandesigntheirwebapplications,neatlypackagetheminaspecialJARfileforwebcomponentscalledaWebApplicationArchivefile,theninstalltheWARsonvariousservershostedbydifferentoperatingsystems(OSes).JavawebcomponentsarenotboundtoasingleOSortoaparticularvendor'sserversoftwarelikeotherweb-relatedsoftwaretechnologies.
Jumpaheadtothepresent.Bylate2003,Javahasachievedstatusasthegranddaddyofserver-sidedevelopment.ServletsandJSPsareincludedintheJava2EnterpriseEdition(J2EE),awidelyacceptedenterprisetechnologyfornetwork-basedanddistributedcomputing.Hundredsofthousandsofdevelopersthroughouttheworldworkonthe"webtier"ofJ2EE-basedtechnologies,usingservlets,JSPs,andsometimesspecialwebframeworkssuchasStruts.
Infact,manywebdevelopersnowspendafairamountoftimegettingtoknowvarious"applicationservers"likeBEAWebLogic,JBoss,orIBM'sWebSpherethatpulltogetherthewebtier,businessordomainobjects(suchascomponentsthathandleweatherdataoracustomer'sfinancialaccounts),andEnterpriseInformationSystems(EIS).TheseapplicationserversrepresentthesoftwarehostforservletsandJSPs.Manywebdevelopers,includingmyself,spendalotoftimeworkingonwebcomponentsthatarehostedonTomcat,apopularopensource(http://www.opensource.org)servletengineand"referenceimplementation"forthenewservletandJSPAPIs.[3]
[3]Areferenceimplementationissoftwarethatisbasedonacommonlyagreeduponspecification,andisfreelyavailabletosoftwaredevelopersandothersasademonstrationofhowthespecifiedsoftwaresystemisdesignedtofunction.
Therapidmaturationandwell-establishednatureofJavahasnaturallyledtoa"cookbook"approachforourbook.Thiscookbookfocusesonhowtoinitiatecertainweb-relatedtasksinJava,ratherthantutoringthereaderonhowtousetheJavalanguage,orexplainingtheservletandJSPAPIsinfinelygraineddetail.Countlesstutorial-orientedJavabooksstillexist,however,inneworreissuedform,whichatteststothepopularityofJavaasaweb-developmentplatform.
What'sintheBook
Increatingtherecipesforthisbook,ItriedtocoverasmanycommonandadvancedwebdevelopertasksasIcouldpracticallyfitintoonebook.Thisamountstoabout230differentrecipes.Eachrecipeshowshowtoimplementaparticulartaskusingservlets,JSPs,and,inmanycases,oneormoresupportingJavaclasses.
Therecipesshowhowto:
Authenticatewebclients
Interactwithdatabases
Sendemail
Handlesubmitteddatafromawebform
Readandset"cookies"
Uploadfilesfromtheclient
IntegrateJavaScriptwithservletsandJSPs
EmbedmultimediafileslikedigitalmoviesandmusicinJSPsandservlets
Handlewebclientswhoseusersspeakdifferentlanguages(internationalization)
LogmessagesfromservletsandJSPs
Dynamicallyincludechunksofcontent,asintraditionalserver-side
include(SSI)code
InteractwithEnterpriseJavaBeans(EJBs)fromaJSPandservlet
UseAmazon.com'sandGoogle.com'sWebServicesAPIsfromaservletorJSP
Ihavealsoincludednumeroustechnology-specificrecipes,suchas:
Using"sessions"inyourJavawebapplications(aconceptthatrepresentsthetrackingofauser'sprogressthroughawebsite)
Workingwith"filters"
UsingtheopensourceANTtooltobuildwebapplications
BindingJavaobjectstoasessionorwebapplicationsotheycanbeusedasinformationordatacontainers
CreatingyourowncustomtagsforJSPs
UsingtheJavaServerPagesStandardTagLibrary(JSTL),whichisalargesetofprebuilttagsyoucanuseinJSPs
Inshort,thebookisdesignedtohelpguideJavawebdevelopersintheireverydaytasks,andtoprovidequicksolutionstotypicalweb-relatedproblems.
BEAWebLogicRecipes
BecauseJavawebdeveloperstendtoworkwithbothTomcatandaproprietaryapplicationserver,I'veincludedanumberofdifferentrecipestoshowhowtoimplementcommontaskswithBEAWebLogic.Asa
practicalmatter,Icouldnotcovertheseveralotherapplicationserversthatareavailable,suchasIBM'sWebSphere,JBoss,Jetty,Oracle9iapplicationserver,orcommercialservletenginessuchasNewAtlantaServletExecandCauchoResin.ButIwantedtoincluderecipescovering"howtheotherhalflives"intermsofusingvariousvendortoolsformanagingeverydayweb-applicationtasks.SolutionsinvolvingthedeploymentorrevisionofwebcomponentsanddeploymentdescriptorsusingvisualinterfacessuchasWebLogic'sAdministrationConsoleorWebLogicBuildercanbequitedifferentfromthoseusedwithTomcat.
Asaresult,thisbookincludesacollectionofbasicWebLogic-relatedrecipes,suchasdeployingwebapplicationsonWebLogic,andusingaservlettoaccessaWebLogicDataSource.Chapter25showshowaservletcaninteractwithanEJBinstalledonWebLogic.
Audience
Therecipesaremainlydesignedforexperienceddeveloperswhodesign,build,deploy,andreviseJava-basedwebapplications.ThisincludesJSP,servlet,andJavaBeandevelopers.
ThebookisalsoappropriateforexperiencedwebdeveloperswhoarejustlearningJavaandmigratingfromanotherwebprogrammingplatform,suchasActiveServerPages,PHP,orPerl.Thesedevelopersareusuallyknowledgableabouttheunderlyingmechanisms,suchassessions,cookies,fileuploads,loginauthentication,andhandlingHTTPPOSTrequests,butmaynotyetknowhowtoimplementthesetasksinJava.Thecookbookallowsthemtoquicklylookupasolutiontoaproblemthattheyhaveprobablyalreadydealtwithusinganotherlanguage.
JavadeveloperswhoneedtoknowhowtoimplementnewservletAPI2.4andJSP2.0features(suchassomeofthenewweb.xmlfilter-mappingelementsforrequestdispatchersandembeddingtheExpressionLanguage[EL]inaJSP'stemplatetext)willalsofindthecookbookhandy.
WhatYouNeedtoKnow
ReadersshouldknowthebasicsoftheJavalanguageorbelearninghowtoprogramwithJava.
Chapter1,includesbriefintroductionstoservlets,JSPs,anddeploymentdescriptorsforreaderswhoarenotyetuptospeedontheseconcepts.However,sincethecookbook'sfocusisonconcisesolutionstospecificproblems,itdoesnotincludelongtutorialsontheservletandJSPAPIs.Eachrecipeincludesanintroductionthatprovidesenoughinformationtogetstartedwiththevarioustechnologiesandcodesamples.Therecipesalsoincludenumerousreferencestoonlineinformationresources,suchasJavadocpagesandtutorials,forreaderswhoneedtoexploreatopic
ingreaterdepth.
ReaderswillbenefitfromhavingalreadybeenintroducedtovariousJ2EEsubjectareassuchasJavaDatabaseConnectivity(JDBC),theJavaNamingandDirectoryInterface(JNDI),andEnterpriseJavaBeans(IhaveincludedonerecipethatinvolvesconnectingawebcomponentwithEJBsusingJNDI).
Finally,aworkingknowledgeofXMLisalsohelpful,asJavawebdevelopmentinvolvesXML-baseddeploymentdescriptorsandconfigurationfiles.
Organization
ThebookbeginswiththreechaptersthatcoverthenutsandboltsofwritingservletsandJSPs,deployingservletsandJSPs,namingorregisteringyourservlets,andusingtheAnttool.
Ithenexploreseveralbasictopicsonwebdevelopment,suchasdynamicallyincludingcontentinwebpages,uploadingfiles,handlingdatathathasbeenpostedfromanHTMLform,readingandsettingcookies,trackingsessions,andintegratingJavaScriptwithJSPsandservlets.
Next,thebookincludessomemoreadvancedrecipes,suchasloggingmessages,authenticatingclients,bindingattributes,workingwiththeclientrequest,andcreatingservletfilters.Chapter20,andChapter21,covertwocommonandcomplexweb-developmenttaskswith20differentrecipes.
Chapter22,andChapter23describecustomtagsandtheJSTL.Chapter24,discussesthecrucialtopicofinternationalizingyourwebapplicationswithservletsandJSPs.
ForwebdeveloperswhosewebcomponentsmustinteractwithEJBsusingtheJavaJNDI,Chapter25,showshowtoconfigureJNDIinbothTomcatandWebLogic,aswellashowtoaccessJNDIobjectsusingbothservers.
ThebookconcludeswithtwochaptersthatdescribedifferentstrategiesforextractingdatafromwebsitesusingJavawebcomponents.Chapter26,hasrecipesonharvestingor"scraping"datafromwebpages.Chapter27,describeshowtouseGoogle'sandAmazon.com'swebservicesAPIs.
ConventionsUsedinThisBook
Thefollowingtypographicalconventionsareusedinthisbook:
Italic
Indicatesnewterms,exampleURLs,emailaddresses,filenames,fileextensions,pathnames,directories,andUnixutilities.
Constantwidth
Indicatescommands,options,switches,variables,attributes,keys,functions,types,classes,namespaces,methods,modules,properties,parameters,values,objects,events,eventhandlers,XMLtags,HTMLtags,macros,thecontentsoffiles,ortheoutputfromcommands.
Constantwidthbold
Showscommandsorothertextthatshouldbetypedliterallybytheuser,andisusedtoemphasizecodeinexamples.
Constantwidthitalic
Showstextthatshouldbereplacedwithuser-suppliedvalues.Insomecaseswheretextisalreadyitalicized,user-suppliedvaluesareshowninangledbrackets(<>)
Thisiconsignifiesatip,suggestion,orgeneralnote.
Thisiconindicatesawarningorcaution.
UsingCodeExamples
Thisbookisheretohelpyougetyourjobdone.Ingeneral,youmayusethecodeinthisbookinyourprogramsanddocumentation.Youdonotneedtocontactusforpermissionunlessyou'rereproducingasignificantportionofthecode.Forexample,writingaprogramthatusesseveralchunksofcodefromthisbookdoesnotrequirepermission.SellingordistributingaCD-ROMofexamplesfromO'Reillybooksdoesrequirepermission.Answeringaquestionbycitingthisbookandquotingexamplecodedoesnotrequirepermission.Incorporatingasignificantamountofexamplecodefromthisbookintoyourproduct'sdocumentationdoesrequirepermission.
O'Reilly&Associatesandtheauthorbothappreciate,butdonotrequire,attribution.Anattributionusuallyincludesthetitle,author,publisher,andISBN.Forexample:"JavaServletandJSPCookbook,byBrucePerry.Copyright2004O'Reilly&Associates,Inc.,0-596-00572-5."
Ifyoufeelyouruseofcodeexamplesfallsoutsidefairuseorthepermissiongivenabove,[email protected].
CommentsandQuestions
Pleaseaddresscommentsandquestionsconcerningthisbooktothepublisher:
O'Reilly&Associates,Inc.1005GravensteinHighwayNorthSebastopol,CA95472(800)998-9938(intheUnitedStatesorCanada)(707)829-0515(internationalorlocal)(707)829-0104(fax)
O'Reillyhasawebpageforthisbook,whereerrata,examples,andanyadditionalinformationislisted.Youcanaccessthispageat:
http://www.oreilly.com/catalog/jsvltjspckbk
Tocommentorasktechnicalquestionsaboutthisbook,sendemailto:
FormoreinformationaboutO'Reillybooks,conferences,ResourceCenters,andtheO'ReillyNetwork,seeourwebsiteat:
http://www.oreilly.com
Acknowledgments
Onenight,morethanayearago,IdispatchedanemailtoO'Reillywithanideaforabook.Atthattime,thelikelihoodthatthiscasualemailwouldeventuallygiverisetoapublishedbookseemedveryremote.Afternumerousemailed"backandforths"betweenmeandacoupleofO'ReillyJavaeditors,andthenseveralmonthsofgentlenudging,solidediting,occasionalreconceptualizations,and(ofcourse)writing,writing,andmorewriting,theseedofthebookideagerminatedandreachedfruition.Voilá,acookbookisborn!
Theshapingofabookisalwaysacollaborationamongseveralpeople.ThisbookprobablywouldnothaveleftthelaunchingpadwithoutmyeditorBrettMcLaughlin'ssuccinctandcontinuousremindersaboutwhatdifferentiatesacookbookfromotherbooktypes.Brettisalsoafine"wordbyword"copyeditor,andhavinganeditorialbackgroundmyself,Iappreciatedhiseffortsfromthewriter'sside.Also,Brett'sknowledgeofJavaisdeep,andhiscommentshelpedmeavoidsomeawkwardcodedesigndecisions.
IamveryfortunatetohaveJasonHunterandSangShinastechnicaleditors.Theyarebothwell-knownJavaexperts,andthisisamuchbetterbooksincetheyhavereadandcommentedonlargechunksofit.Theirreviewhadareallyshortdeadline,andthisisabigbook.Iwasamazedatthecomprehensivecoveragewithsuchashortturnaround.Asatechnicalwriter,Iamindebtedtothosewhorescuemefromembarrassingmistakes!
Someofussaveourfamilymembersforlastinacknowledgingthosewhohelpus.Maybethatisbecausethelastparagraphisthefoundationonwhichtherestofthelanguagesits,justasthefamilyiseverywriter'sfoundation,givingthemsupportandshieldingthemfromdistractionsastheyimmersethemselvesinproseandtechnology.ThisbookwouldnothavebeencreatedwithoutthehelpfrommywifeStacy,daughterRachel,andevenScott,whoinspiresmefromthetendervantagepointofbeinglessthanoneyearold.I'llalsorepeatwhatIsaidinmyAppleScriptbook;
IthankmyparentsRobertandAnnePerryforinstallinginmealoveofwritingandbooks.
Chapter1.WritingServletsandJSPs
Introduction
Recipe1.1.WritingaServlet
Recipe1.2.WritingaJSP
Recipe1.3.CompilingaServlet
Recipe1.4.PackagingServletsandJSPs
Recipe1.5.CreatingtheDeploymentDescriptor
Introduction
Thepurposeofthischapteristobringrelativenewcomersuptospeedinwriting,compiling,andpackagingservletsandJSPs.IfyouhaveneverdevelopedaservletorJSPbefore,orjustneedtobrushuponthetechnologytojumpstartyourdevelopment,thentheupcomingrecipesprovidesimpleprogrammingexamplesandanoverviewofthecomponentsthatyourequireontheuserclasspathtocompileservlets.
Recipe1.1andRecipe1.2provideabriefintroductiontoservletsandJSPs,respectively.AcomprehensivedescriptionofaservletorJSP'sroleintheJava2Platform,EnterpriseEdition(J2EE),isbeyondthescopeoftheserecipes.However,informationthatrelatesdirectlytoJ2EEtechnology,suchasdatabasesandJDBC;usingservletswiththeJavaNamingandDirectoryInterface(JNDI);andusingservletswithJavaMail(oremail)isdistributedthroughoutthebook(andindex!).
The"SeeAlso"sectionsconcludingeachrecipeprovidepointerstocloselyrelatedchapters,anonlinetutorialmanagedbySunMicrosystems,andotherO'Reillybooksthatcoverthesetopicsindepth.
Recipe1.1WritingaServlet
Problem
Youwanttowriteaservletthatispartofawebapplication.
Solution
CreateaJavaclassthatextendsjavax.servlet.http.HttpServlet.Makesuretoimporttheclassesfromservlet.jar(orservlet-api.jar)you'llneedthemtocompiletheservlet.
Discussion
AservletisaJavaclassthatisdesignedtorespondwithdynamiccontenttoclientrequestsoveranetwork.IfyouarefamiliarwithCommonGatewayInterface(CGI)programs,thenservletsareaJavatechnologythatcanreplaceCGIprograms.Oftencalledawebcomponent(alongwithJSPs),aservletisexecutedwithinaruntimeenvironmentprovidedbyaservletcontainerorwebcontainersuchasJakartaTomcatorBEAWebLogic.
Awebcontainercanbeanadd-oncomponenttoanHTTPserver,oritcanbeastandaloneserversuchasTomcat,whichiscapableofmanagingHTTPrequestsforbothstaticcontent(HTMLfiles)aswellasforservletsandJSPs.
Servletsareinstalledinwebcontainersaspartofwebapplications.
TheseapplicationsarecollectionsofwebresourcessuchasHTMLpages,images,multimediacontent,servlets,JavaServerPages,XMLconfigurationfiles,Javasupportclasses,andJavasupportlibraries.Whenawebapplicationisdeployedinawebcontainer,thecontainercreatesandloadsinstancesoftheJavaservletclassintoitsJavaVirtualMachine(JVM)tohandlerequestsfortheservlet.
Aservlethandleseachrequestasaseparatethread.Therefore,servletdevelopershavetoconsiderwhethertosynchronizeaccesstoinstancevariables,classvariables,orsharedresourcessuchasadatabaseconnection,dependingonhowtheseresourcesareused.
Allservletsimplementthejavax.servlet.Servletinterface.Webapplicationdeveloperstypicallywriteservletsthatextendjavax.servlet.http.HttpServlet,anabstractclassthatimplementstheServletinterfaceandisspeciallydesignedtohandleHTTPrequests.
Thefollowingbasicsequenceoccurswhenthewebcontainercreatesaservletinstance:
1. Theservletcontainercallstheservlet'sinit()method,whichisdesignedtoinitializeresourcesthattheservletmightuse,suchasalogger(seeChapter14).Theinit()methodgetscalledonlyonceduringtheservlet'slifetime.
Theinit()methodinitializesanobjectthatimplementsthejavax.servlet.ServletConfiginterface.Thisobjectgivestheservletaccesstoinitializationparametersdeclaredinthedeploymentdescriptor(seeRecipe1.5).ServletConfigalsogivestheservletaccesstoajavax.servlet.ServletContextobject,withwhichtheservletcanlogmessages,dispatchrequeststootherwebcomponents,andgetaccesstootherwebresourcesinthesameapplication(seeRecipe13.5).
Servletdevelopersarenotrequiredtoimplementtheinit()methodintheirHttpServletsubclasses.
3. Theservletcontainercallstheservlet'sservice()methodinresponsetoservletrequests.IntermsofHttpServlets,service()automaticallycallstheappropriateHTTPmethodtohandletherequestbycalling(generally)theservlet'sdoGet()ordoPost()methods.Forexample,theservletrespondstoausersendingaPOSTHTTPrequestwithadoPost()methodexecution.
WhencallingthetwoprincipalHttpServletmethods,doGet()ordoPost(),theservletcontainercreatesjavax.servlet.http.HttpServletRequestandHttpServletResponseobjectsandpassestheminasparameterstotheserequesthandlermethods.HttpServletRequestrepresentstherequest;HttpServletResponseencapsulatestheservlet'sresponsetotherequest.
Example1-1showsthetypicalusesoftherequestandresponseobjects.ItisagoodideatoreadtheservletAPIdocumentation(athttp://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/package-summary.html),asmanyofthemethodnames(e.g.,request.getContextPath())areself-explanatory.
5. Theservletorwebcontainer,notthedeveloper,managestheservlet'slifecycle,orhowlonganinstanceoftheservletexistsintheJVMtohandlerequests.Whentheservletcontainerissettoremovetheservletfromservice,itcallstheservlet'sdestroy()method,inwhichtheservletcanreleaseany
resources,suchasadatabaseconnection.
Example1-1showsatypicalservletidiomforhandlinganHTMLform.ThedoGet()methoddisplaystheformitself.ThedoPost()methodhandlesthesubmittedformdata,sinceindoGet(),theHTMLformtagspecifiestheservlet'sownaddressasthetargetfortheformdata.
Theservlet(namedFirstServlet)specifiesthatthedeclaredclassispartofthecom.jspservletcookbookpackage.Itisimportanttocreatepackagesforyourservletsandutilityclasses,andthentostoreyourclassesinadirectorystructurebeneathWEB-INFthatmatchesthesepackagenames.
TheFirstServletclassimportsthenecessaryclassesforcompilingabasicservlet,whicharetheemphasizedimportstatementsinExample1-1.TheJavaclassextendsHttpServlet.TheonlydefinedmethodsaredoGet(),whichdisplaystheHTMLforminresponsetoaGETHTTPrequest,anddoPost(),whichhandlestheposteddata.
Example1-1.AtypicalHttpServletusedforhandlinganHTMLform
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.util.Enumeration;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
publicclassFirstServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
//useaPrintWritertosendtextdatatotheclientwhohasrequestedthe
//servlet
java.io.PrintWriterout=response.getWriter();
//BeginassemblingtheHTMLcontent
out.println("<html><head>");
out.println("<title>HelpPage</title></head><body>");
out.println("<h2>Pleasesubmityourinformation</h2>");
//makesuremethod="post"sothattheservletservicemethod
//callsdoPostintheresponsetothisformsubmit
out.println(
"<formmethod=\"post\"action=\""+request.getContextPath()+
"/firstservlet\">");
out.println("<tableborder=\"0\"><tr><tdvalign=\"top\">");
out.println("Yourfirstname:</td><tdvalign=\"top\">");
out.println("<inputtype=\"text\"name=\"firstname\"size=\"20\">");
out.println("</td></tr><tr><tdvalign=\"top\">");
out.println("Yourlastname:</td><tdvalign=\"top\">");
out.println("<inputtype=\"text\"name=\"lastname\"size=\"20\">");
out.println("</td></tr><tr><tdvalign=\"top\">");
out.println("Youremail:</td><tdvalign=\"top\">");
out.println("<inputtype=\"text\"name=\"email\"size=\"20\">");
out.println("</td></tr><tr><tdvalign=\"top\">");
out.println("<inputtype=\"submit\"value=\"SubmitInfo\"></td></tr>");
out.println("</table></form>");
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//displaytheparameternamesandvalues
EnumerationparamNames=request.getParameterNames();
StringparName;//thiswillholdthenameoftheparameter
booleanemptyEnum=false;
if(!paramNames.hasMoreElements())
emptyEnum=true;
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
//useaPrintWritertosendtextdatatotheclient
java.io.PrintWriterout=response.getWriter();
//BeginassemblingtheHTMLcontent
out.println("<html><head>");
out.println("<title>SubmittedParameters</title></head><body>");
if(emptyEnum){
out.println(
"<h2>Sorry,therequestdoesnotcontainanyparameters</h2>");
}else{
out.println(
"<h2>Herearethesubmittedparametervalues</h2>");
}
while(paramNames.hasMoreElements()){
parName=(String)paramNames.nextElement();
out.println(
"<strong>"+parName+"</strong>:"+
request.getParameter(parName));
out.println("<br/>");
}//while
out.println("</body></html>");
}//doPost
}
YoumighthavenoticedthatdoGet()anddoPost()eachthrowServletExceptionandIOException.TheservletthrowsIOExceptionbecausetheresponse.getWriter()(aswellasPrintWriter.close())methodcallcanthrowanIOException.ThedoPost()anddoGet()methodscanthrowaServletExceptiontoindicatethataproblemoccurredwhenhandlingtherequest.Forexample,iftheservletdetectedasecurityviolationorsomeotherrequestproblem,thenitcouldincludethefollowingcodewithindoGet()ordoPost():
//detectsaproblemthatpreventsproperrequesthandling...
thrownewServletException("Theservletcannothandlethisrequest.");
Figure1-1showstheoutputdisplayedbytheservlet'sdoGet()methodinabrowser.
Figure1-1.Theservlet'soutputfordoGet()method
Figure1-2showstheservlet'soutputforthedoPost()method.
Figure1-2.Theservlet'soutputforthedoPost()method
SeeAlso
Recipe1.3oncompilingaservlet;Recipe1.4onpackagingservletsandJSPs;Recipe1.5oncreatingthedeploymentdescriptor;Chapter2on
deployingservletsandJSPs;Chapter3onnamingservlets;thejavax.servlet.httppackageJavaDoc:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/package-summary.html;theJ2EEtutorialfromSunMicrosystems:http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/J2eeTutorialTOC.html;JasonHunter'sJavaServletProgramming(O'Reilly).
Recipe1.2WritingaJSP
Problem
YouwanttocreateaJSPandincludeitinawebapplication.
Solution
CreatetheJSPasatextfileusingHTMLtemplatetextasneeded.StoretheJSPfileatthetoplevelofthewebapplication.
Discussion
AJavaServerPages(JSP)componentisatypeofJavaservletthatisdesignedtofulfilltheroleofauserinterfaceforaJavawebapplication.WebdeveloperswriteJSPsastextfilesthatcombineHTMLorXHTMLcode,XMLelements,andembeddedJSPactionsandcommands.JSPswereoriginallydesignedaroundthemodelofembeddedserver-sidescriptingtoolssuchasMicrosoftCorporation'sASPtechnology;however,JSPshaveevolvedtofocusonXMLelements,includingcustom-designedelements,orcustomtags,astheprincipalmethodofgeneratingdynamicwebcontent.
JSPfilestypicallyhavea.jspextension,asinmypage.jsp.WhenaclientrequeststheJSPpageforthefirsttime,orifthedeveloperprecompilestheJSP(seeChapter5),thewebcontainertranslatesthetextualdocumentintoaservlet.
TheJSP2.0specificationreferstotheconversionofaJSPintoaservletasthetranslationphase.WhentheJSP(nowaservletclass)respondstorequests,thespecificationcallsthisstagetherequestphase.Theresultingservletinstanceis
calledthepageimplementationobject.
AJSPcompiler(suchasTomcat'sJaspercomponent)automaticallyconvertsthetext-baseddocumentintoaservlet.Thewebcontainercreatesaninstanceoftheservletandmakestheservletavailabletohandlerequests.Thesetasksaretransparenttothedeveloper,whoneverhastohandlethetranslatedservletsourcecode(althoughtheycanexaminethecodetofindoutwhat'shappeningbehindthescenes,whichisalwaysinstructive).
ThedeveloperfocusesontheJSP'sdynamicbehaviorandwhichJSPelementsorcustom-designedtagssheusestogeneratetheresponse.DevelopingtheJSPasatext-baseddocumentratherthanJavasourcecodeallowsaprofessionaldesignertoworkonthegraphics,HTML,ordynamicHTML,leavingtheXMLtagsanddynamiccontenttoprogrammers.
Example1-2showsaJSPthatdisplaysthecurrentdateandtime.TheexampleJSPshowshowtoimportanduseacustomtaglibrary,whichChapter23describesingreatdetail.Thecodealsousesthejsp:useBeanstandardaction,abuilt-inXMLelementthatyoucanusetocreateanewJavaobjectforuseintheJSPpage.HerearethebasicstepsforwritingaJSP:
1. Openupatexteditor,oraprogrammer'seditorthatoffersJSPsyntaxhighlighting.
IfyouaredevelopingaJSPforhandlingHTTPrequests,theninputtheHTMLcodejustasyouwouldforanHTMLfile.
IncludeanynecessaryJSPdirectives,suchasthetaglibdirectiveinExample1-2,atthetopofthefile.Adirectivebeginswiththe<%@s.
Typeinthestandardactionsorcustomtagswherevertheyare
needed.
Savethefilewitha.jspextensioninthedirectoryyouhavedesignatedforJSPs.Atypicallocationisthetop-leveldirectoryofawebapplicationthatyouaredevelopinginyourfilesystem.
SomeJSPsaredevelopedasXMLfiles,orJSPdocuments,consistingsolelyofwell-formedXMLelementsandtheirattributes.TheJSP2.0specificationrecommendsthatyougivethesefilesa.jspxextension.SeeRecipe5.5forfurtherdetailsonJSPdocuments.
Example1-2.AJSPfilethatdisplaysthedate
<%--usethe'taglib'directivetomaketheJSTL1.0coretagsavailable;usetheuri
"http://java.sun.com/jsp/jstl/core"forJSTL1.1--%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%--usethe'jsp:useBean'standardactiontocreatetheDateobject;theobjectisset
asanattributeinpagescope
--%>
<jsp:useBeanid="date"class="java.util.Date"/>
<html>
<head><title>FirstJSP</title></head>
<body>
<h2>Hereistoday'sdate</h2>
<c:outvalue="${date}"/>
</body>
</html>
Toviewtheoutputofthisfileinabrowser,requestthefilebytypingthe
URLintothebrowserlocationfield,asin:http://localhost:8080/home/firstJ.jsp.ThenameofthefileisfirstJ.jsp.IfthisisthefirsttimethatanyonehasrequestedtheJSP,thenyouwillnoticeadelayastheJSPcontainerconvertsyourtextfileintoJavasourcecode,thencompilesthesourceintoaservlet.
YoucanavoiddelaysbyprecompilingtheJSP.IfyourequesttheJSPwithajsp_precompile=trueparameter,TomcatconvertstheJSP,butdoesnotsendbackaresponse.Anexampleishttp://localhost:8080/home/firstJ.jsp?jsp_precompile=true.
Figure1-3showstheJSPoutputinabrowser.
Figure1-3.OutputfromthefirstJ.jsppage
Ifyouselect"ViewSource"fromthebrowsermenutoviewthepage'ssourcecode,youwon'tseeanyofthespecialJSPsyntax:thecommentcharacters(<%----%>),thetaglibdirective,thejsp:useBeanaction,orthec:outtag.Theservletsendsonlythetemplatetextandthegenerateddatestringtotheclient.
SeeAlso
Recipe5.1-Recipe5.3onprecompilingJSPs;Chapter2ondeployingservletsandJSPs;Recipe1.1andRecipe1.3onwritingandcompilingaservlet;Recipe1.4onpackagingservletsandJSPs;Recipe1.5oncreatingthedeploymentdescriptor;theJ2EEtutorialfromSunMicrosystems:http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/J2eeTutorialTOC.html;HansBergsten'sJavaServerPages(O'Reilly).
Recipe1.3CompilingaServlet
Problem
Youhavewrittenaservlet,andnowyouwanttocompileitintoaclassfile.
Solution
Makesurethatservlet.jar(forTomcat4.1.24)orservlet-api.jar(forTomcat5)isonyouruserclasspath.UsejavacasyouwouldforanyotherJavasourcefile.
Discussion
Ataminimum,youhavetoplacetheservletclassesonyourclasspathinordertocompileaservlet.TheseclassesarelocatedintheseJavapackages:
javax.servlet
javax.servlet.http
Tomcat5supportstheservletAPI2.4;theJARfilethatyouneedontheclasspathislocatedat<Tomcat-5-installation-directory>/common/lib/servlet-api.jar.Tomcat4.1.24usestheservlet2.3API.Theservletclassesarelocatedat:<Tomcat-4-installation-directory>/common/lib/servlet.jar.
ForBEAWebLogic7.0,theservletclassesandmanyothersubpackages
ofthejavaxpackage(e.g.,javax.ejb,javax.mail,javax.sql)arelocatedat:<WebLogic-installation-directory>/weblogic700/server/lib/weblogic.jar.
IfyouareusingAnttocompileservletclasses,thenproceedtoRecipe4.4,donotpassGo,donotcollect$200.ThatrecipeisdevotedspecificallytothetopicofusingAnttocompileaservlet.IfyouuseanIDE,followitsinstructionsforplacingaJARfileontheclasspath.
Thefollowingcommandlinecompilesaservletinthesrcdirectoryandplacesthecompiledclass,nestedwithinitspackage-relateddirectories,inthebuilddirectory:
javac-classpathK:\tomcat5\jakarta-tomcat-5\dist\common\lib\servlet-api.jar
-d./build./src/FirstServlet.java
Forthiscommandlinetorunsuccessfully,youmustchangetotheparentdirectoryofthesrcdirectory.
Recipe1.4explainsthetypicaldirectorystructure,includingthesrcdirectory,fordevelopingawebapplication.
Iftheservletdependsonanyotherlibraries,youhavetoincludethoseJARfilesonyourclasspathaswell.Ihaveincludedonlytheservlet-api.jarJARfileinthiscommandline.
YoualsohavetosubstitutethedirectorypathforyourowninstallationofTomcatforthislineofthepriorcommand-linesequence:
K:\tomcat5\jakarta-tomcat-5\dist\common\lib\servlet-api.jar
Thiscommandlineusesthebuilt-injavaccompilerthatcomeswiththe
SunMicrosystemsJavaSoftwareDevelopmentKit(JDK).Forthiscommandtoworkproperly,youhavetoincludethelocationoftheJavaSDKthatyouareusinginthePATHenvironmentvariable.Forexample,onaUnix-basedMacOSX10.2system,thedirectorypath/usr/binmustbeincludedinthePATHvariable.OnmyWindowsNTmachine,thePATHincludesh:\j2sdk1.4.1_01\bin.
SeeAlso
Chapter2ondeployingservletsandJSPs;Chapter3onnamingservlets;Recipe1.4onpackagingservletsandJSPs;Recipe1.5oncreatingthedeploymentdescriptor;theJ2EEtutorialfromSunMicrosystems:http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/J2eeTutorialTOC.html;JasonHunter'sJavaServletProgramming(O'Reilly).
Recipe1.4PackagingServletsandJSPs
Problem
YouwanttosetupadirectorystructureforpackagingandcreatingaWebARchive(WAR)fileforservletsandJSPs.
Solution
Setupadirectorystructureinyourfilesystem,thenusethejartoolorAnttocreatetheWAR.
Discussion
Exceptintherarestofcircumstances,you'llusuallydevelopaservletorJSPaspartofawebapplication.Itisrelativelyeasytosetupadirectorystructureonyourfilesystemtoholdweb-applicationcomponents,whichincludeHTMLfiles,servlets,JSPs,graphics,JARlibraries,possiblymoviesandsoundfiles,aswellasXMLconfigurationfiles(suchasthedeploymentdescriptor;seeRecipe1.5).
Thesimplestorganizationforthisstructureistocreatetheexactlayoutofawebapplicationonyourfilesystem,thenusethejartooltocreateaWARfile.
AWARfileislikeaZIParchive.YoudeployyourwebapplicationintoawebcontainerbydeployingtheWAR.SeeChapter2forrecipesaboutvariousdeploymentscenarios.
ThewebapplicationstructureinvolvingtheWEB-INFsubdirectoryisstandardtoallJavawebapplicationsandspecifiedbytheservletAPIspecification(inthesectionnamedWebApplications.Hereiswhatthisdirectorystructurelookslike,givenatop-leveldirectorynameofmyapp:
/myapp
/images
/WEB-INF
/classes
/lib
TheservletspecificationspecifiesaWEB-INFsubdirectoryandtwochilddirectories,classesandlib.TheWEB-INFsubdirectorycontainstheapplication'sdeploymentdescriptor,namedweb.xml.TheJSPfilesandHTMLliveinthetop-leveldirectory(myapp).Servletclasses,JavaBeanclasses,andanyotherutilityclassesarelocatedintheWEB-INF/classesdirectory,inastructurethatmatchestheirpackagename.Ifyouhaveafullyqualifiedclassnameofcom.myorg.MyServlet,thenthisservletclassmustbelocatedinWEB-INF/classes/com/myorg/MyServlet.class.
TheWEB-INF/libdirectorycontainsanyJARlibrariesthatyourwebapplicationrequires,suchasdatabasedrivers,thelog4j.jar,andtherequiredJARsforusingtheJavaServerPagesStandardTagLibrary(seeChapter23).
OnceyouarereadytotesttheapplicationinWARformat,changetothetop-leveldirectory.Typethefollowingcommand,namingtheWARfileafterthetop-leveldirectoryofyourapplication.Thesecommand-linephrasesworkonbothWindowsandUnixsystems(IusedthemwithWindowsNT4andMacOSX10.2):
jarcvfmyapp.war.
Don'tforgetthefinaldot(.)character,whichspecifiestothejartooltoincludethecurrentdirectory'scontentsanditssubdirectoriesintheWARfile.Thiscommandcreatesthemyapp.warfileinthecurrentdirectory.
TheWARnamebecomestheapplicationnameandcontextpathforyourwebapplication.Forexample,myapp.waristypicallyassociatedwithacontextpathof/myappwhenyoudeploytheapplicationtoawebcontainer.
IfyouwanttoviewthecontentsoftheWARatthecommandline,typethis:
jartvfalpine-final.war
IftheWARfileisverylargeandyouwanttoviewitscontentsonepageatatime,usethiscommand:
jartvfalpine-final.war|more
Hereisexampleoutputfromthiscommand:
H:\classes\webservices\finalproj\dist>jartvfalpine-final.war
0MonNov1814:10:36EST2002META-INF/
48MonNov1814:10:36EST2002META-INF/MANIFEST.MF
555TueNov0517:08:16EST2002request.jsp
914MonNov1808:53:00EST2002response.jsp
0MonNov1814:10:36EST2002WEB-INF/
0MonNov1814:10:36EST2002WEB-INF/classes/
0TueNov0511:09:34EST2002WEB-INF/classes/com/
0TueNov0511:09:34EST2002WEB-INF/classes/com/parkerriver/
CONTINUED...
ManydevelopmentteamsareusingAnttocompileandcreateWARfilesfortheirservletsandJSPs.Recipe2.6describesusingAntfordevelopingandupdatingwebapplications.
Ijumpstartyourprogresstowardthatrecipebyshowingthekindofdirectorystructureyoumightuseforacomprehensivewebapplication,onethatcontainsnumerousservlets,JSPs,staticHTMLfiles,aswellasvariousgraphicsandmultimediacomponents.WhenusingAnttobuildaWARfilefromthiskindofdirectorystructure,youcanfilteroutthe
directoriesthatyoudonotwanttoincludeinthefinalWAR,suchasthetop-levelsrc,dist,andmetadirectories.
myapp
/build
/dist
/lib
/meta
/src
/web
/images
/multimedia
/WEB-INF
/classes
/lib
/tlds
/jspf
TheWEB-INF/tldsandWEB-INF/jspfoptionaldirectoriesmaycontainTagLibraryDescriptorfilesandJSPfragments(chunksofJSPsthataredesignedtobeincludedinotherJSPs,suchasserver-sideincludes),respectively.
SeeAlso
Chapter2ondeployingservletsandJSPs;Chapter3onnamingservlets;ThedeploymentsectionsofTomcat:TheDefinitiveGuide,byBrittainandDarwin(O'Reilly);theJ2EEtutorialfromSunMicrosystems:http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/J2eeTutorialTOC.html.
Recipe1.5CreatingtheDeploymentDescriptor
Problem
Youwanttocreatethedeploymentdescriptorforyourapplication.
Solution
NametheXMLfileweb.xmlandplaceitintheWEB-INFdirectoryofyourwebapplication.Ifyoudonothaveanexistingexampleofweb.xml,thencutandpastetheexamplesgivenintheservletv2.3or2.4specificationsandstartfromthere.
Discussion
Thedeploymentdescriptorisaveryimportantpartofyourwebapplication.ItconveystherequirementsforyourwebapplicationinaconciseformatthatisreadablebymostXMLeditors.Theweb.xmlfileiswhereyou:
RegisterandcreateURLmappingsforyourservlets
Registerorspecifyanyoftheapplication'sfiltersandlisteners
Specifycontextinitparametername/valuepairs
Configureerrorpages
Specifyyourapplication'swelcomefiles
Configuresessiontimeouts
Specifiysecuritysettingsthatcontrolwhocanrequestwhichwebcomponents
Thisisjustasubsetoftheconfigurationsthatyoucanusewithweb.xml.Whileanumberofchaptersinthisbookcontaindetailedexamplesofweb.xml(refertothe"SeeAlso"section),thisrecipeshowssimplifiedversionsoftheservletv2.3andv2.4deploymentdescriptors.
Example1-3showsasimplewebapplicationwithaservlet,afilter,alistener,andasession-configelement,aswellasanerror-pageconfiguration.Theweb.xmlinExample1-3usestheservletv2.3DocumentTypeDefinition(DTD).Themaindifferencebetweenthedeploymentdescriptorsof2.3and2.4isthat2.3usesaDTDand2.4isbasedonanXMLschema.You'llnoticethattheoldversionofweb.xmlhastheDOCTYPEdeclarationatthetopofthefile,whilethe2.4versionusesthenamespaceattributesoftheweb-appelementtorefertotheXMLschema.TheXMLelementsofExample1-3havetobeinthesameorderasspecifiedbytheDTD.
Example1-3.ThedeploymentdescriptorforservletAPI2.3
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<display-name>Servlet2.3deploymentdescriptor</display-name>
<filter>
<filter-name>RequestFilter</filter-name>
<filter-class>com.jspservletcookbook.RequestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RequestFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.jspservletcookbook.ReqListener</listener-class>
</listener>
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.jspservletcookbook.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myservlet</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>15</session-timeout>
</session-config>
<error-page>
<error-code>404</error-code>
<location>/err404.jsp</location>
</error-page>
</web-app>
Example1-3showstheweb.xmlfileforanapplicationthathasjustoneservlet,accessedatthepath<contextpath>/myservlet.Sessionstimeoutin15minuteswiththisapplication.IfaclientrequestsaURLthat
cannotbefound,thewebcontainerforwardstherequesttothe/err404.jsppage,basedontheerror-pageconfiguration.ThefilternamedRequestFilterappliestoallrequestsforstaticanddynamiccontentinthiscontext.Atstartup,thewebcontainercreatesaninstanceofthelistenerclasscom.jspservletcookbook.ReqListener.
EverythingaboutExample1-4isthesameasExample1-3,exceptthattheweb-appelementatthetopofthefilereferstoanXMLschemawithitsnamespaceattributes.Inaddition,elementscanappearinarbitraryorderwiththeservletv2.4deploymentdescriptor.Forinstance,ifyouweresoinclinedyoucouldlistyourservletsandmappingsbeforeyourlistenersandfilters.
Example1-4.Aservletv2.4deploymentdescriptor
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<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_2_4.xsd"version="2.4">
<!--therestofthefileisthesameasExample1-3aftertheweb-appopeningtag-->
</web-app>
Theservlet2.4versionofthedeploymentdescriptoralsocontainsdefinitionsforvariouselementsthatarenotincludedintheservlet2.3web.xmlversion:jsp-config,message-destination,message-destination-ref,andservice-ref.ThesyntaxfortheseelementsappearsinthespecificationsforJSPv2.0andJ2EEv1.4.
SeeAlso
Chapter2ondeployingservletsandJSPs;Chapter3onnamingservlets;Chapter9onconfiguringthedeploymentdescriptorforerrorhandling;theJ2EEtutorialfromSunMicrosystems:http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/J2eeTutorialTOC.html.
Chapter2.DeployingServletsandJSPs
Introduction
Recipe2.1.DeployinganIndividualServletonTomcat
Recipe2.2.UsingaContextElementinTomcat'sserver.xml
Recipe2.3.DeployinganIndividualServletonWebLogic
Recipe2.4.DeployinganIndividualJSPonTomcat
Recipe2.5.DeployinganIndividualJSPonWebLogic
Recipe2.6.DeployingaWebApplicationonTomcat
Recipe2.7.DeployingaWebApplicationonWebLogicUsingAnt
Recipe2.8.UsingtheWebLogicAdministrationConsole
Recipe2.9.UsingWebLogicBuildertoDeployaWebApplication
Recipe2.10.Usingtheweblogic.DeployerCommand-LineTool
Introduction
ThischapterdescribeshowtotakeservletsorJavaServerPages(JSPs)andmakethemavailabletoreceivewebrequestsonTomcat'sservletcontainerorBEAWebLogicServer7.0.ThisdiscussionbeginswithdeployingservletsandJSPs;inotherwords,gettingthemrunningonTomcatorWebLogic,eitheraloneoraspartofawebapplication.
DevelopingandcompilingaservletorJSPwithinanintegrateddevelopmentenvironment(IDE)isonething.HavingthewebcomponentrespondtoHTTPrequestsisanother.Thisiswhatdeploymentisallaboutwithweb-relatedsoftware:placingthesoftwareintoservicewithinawebcontainerlikeTomcatoranapplicationserversuchasBEAWebLogicServer7.0.ThefollowingrecipesdetaildeploymentofservletsandJSPsonthesewebcontainers,firstindividually,andthenaspartofawebapplication.
ThewonderfulopensourceJakartaAntbuildandautomationtooliscommonlyusedforthispurpose.Itismentionedwhereveritisrelevantinthefollowingrecipes,andChapter4iscompletelydevotedtoinstallingandusingAnt.
Recipe2.1DeployinganIndividualServletonTomcat
Problem
YouwanttotakeacompiledservletandinstallitinTomcattofindoutifitisworking.Youaredoingapreliminarytestanddonotwanttotakethetimetobuildacompletewebapplicationfortheservlet.
Solution
CopyandpastetheclassfileintoTomcat'sdefaultwebapplication(orintoawebapplicationthatyouhavealreadyinstalled),thenrequestitusingtheinvokerservlet.OruseanAntbuild.xmlfiletomovethefiletemporarilyintotheTomcatdefaultwebapplication.
Discussion
Sometimesyoudesignaservletandareanxioustoseeiftheservletworks.Unlesstheservletdependsonotherservletsorcomponentsintheapplication,youcantestitonTomcatbypastingtheclassfile(includingitspackage-relateddirectories)intothedefaultTomcatwebapplication.Bydefault,thisapplicationislocatedatthepath<Tomcat-installation-directory>/webapps/ROOT.
Ifthefullyqualifiedclassnameoftheservletisjspservletcookbook.CookieServlet,thenhereistheentireprocessformanuallygettingasingleservletgoingonTomcat:
ShutdowntheTomcatserverbyexecutingtheshellscript<tomcat-
installation-directory>/bin/shutdownorbyexecutingashellscriptyourserveradministratorhasprovided.Analternativeisto"stop"thedefaultapplicationbyrequestingthisURLinyourbrowser:http://localhost:8080/manager/stop?path=/.
Createthejspservletcookbookdirectoryinthe<Tomcat-installation-directory>/webapps/ROOT/WEB-INF/classesdirectory(maketheclassesdirectoryifitdoesnotalreadyexist).
PastetheCookieServletclassfileintothe<Tomcat-installation-directory>/webapps/ROOT/WEB-INF/classes/jspservletcookbookdirectory.
StartuptheTomcatserverbyexecutingtheshellscript<Tomcat-installation-directory>/bin/startuporashellscriptthatyourserveradministratorhasprovided.AnalternativeistostartthedefaultapplicationbyrequestingthisURLinyourbrowser:http://localhost:8080/manager/start?path=/.
RequesttheservletinyourbrowserwiththeURLhttp://localhost:8080/servlet/jspservletcookbook.CookieServlet.
Bynowyouareprobablysaying,"Theremustbeamoreelegantalternativetothisslow,manualinstallationofasingleservlet!"Youarecorrect,andcanuseJakartaAnttoconvertthismanualprocesstoanautomatedone.
Thebuild.xmlfileinExample2-1accomplishesthesametestingprocess,assumingyouhavedownloadedandinstalledAntasdescribedinChapter4.Placethisbuildfileinaconvenientdirectory.Createinthatdirectoryaglobal.propertiesfilethatiscustomizedaccordingtoyourneeds(seeExample2-2).Changetothatdirectoryinacommand-linewindowandtypeant.Anttakescareoftherestofthetasks,includingstartingandstoppingTomcat'sdefaultwebapplication.
Example2-1.Installingaservletinthedefaultwebapplication
<projectname="Cookbook"default="deploy-servlet"basedir=".">
<taskdefname="start"classname="org.apache.catalina.ant.StartTask"/>
<taskdefname="stop"classname="org.apache.catalina.ant.StopTask"/>
<!--Loadinsomeglobalproperties-->
<propertyfile="global.properties"/>
<targetname="init"description="Initializessomeproperties.">
<echomessage="Initializingproperties."/>
<propertyname="build"value=".\build"/>
<propertyname="src"value=".\src"/>
<!--Thecontext-pathisjustaslashcharacterwhenitistheROOTapplication;
seethestartandstoptargets,whichalreadyincludetheslashaspartof
theURLpattern-->
<propertyname="context-path"value=""/>
</target>
<targetname="prepare"depends="init">
<echomessage="Cleaningupthebuilddirectory."/>
<deletedir="${build}"/>
<mkdirdir="${build}"/>
</target>
<!--SettheCLASSPATHtovariousTomcat.jarfiles-->
<pathid="classpath">
<filesetdir="${tomcat.dir}/common/lib">
<includename="*.jar"/>
</fileset>
<filesetdir="${tomcat.dir}/common/endorsed">
<includename="*.jar"/>
</fileset>
</path>
<!--startthedefaultTomcatwebapplication-->
<targetname="start"
description="StartsthedefaultWebapplication">
<echomessage="Startingthedefaultapplication...."/>
<start
url="${url}"
username="${username}"
password="${password}"
path="/${context-path}"
/>
</target>
<!--stopthedefaultTomcatwebapplication-->
<targetname="stop"
description="StopsthedefaultWebapplication">
<echomessage="Stoppingtheapplication...."/>
<stop
url="${url}"
username="${username}"
password="${password}"
path="/${context-path}"
/>
</target>
<!--stopthedefaultTomcatwebapplication,compileyourservlet,addittothedefault
Webapplication,thenstartthedefaultwebapplication-->
<targetname="deploy-servlet"depends="prepare"
description=
"Compilethespecifiedservlet,thenmoveitintoTomcat'sdefault
Webapplication.">
<echomessage="StoppingthedefaultTomcatapplication...."/>
<antcalltarget="stop"/>
<echomessage="Compilingtheservlet...."/>
<javacsrcdir="${src}"destdir="${build}">
<includename="${compiled.servlet}.java"/>
<classpathrefid="classpath"/>
</javac>
<echomessage=
"CopyingtheservlettoTomcatROOTwebapplication..."/>
<copytodir="${tomcat.webapps}/WEB-INF/classes">
<filesetdir="${build}"/>
</copy>
<echomessage="Startingthedefaultapplication...."/>
<antcalltarget="start"/>
</target>
</project>
Theglobal.propertiesfilethatsitsinthesamedirectoryasbuild.xmllookslikeExample2-2.
Example2-2.global.propertiesfileforAnt
tomcat.webapps=k:/jakarta-tomcat-4.1.12/webapps/ROOT
tomcat.dir=k:/jakarta-tomcat-4.1.12
url=http://localhost:8080/manager
compiled.servlet=CookieServlet
username=tomcat
password=tomcat
global.propertiesisjustalistofproperty-name=valuepairs.Inotherwords,eachlineiscomposedofastringofcharactersthatrepresentsthepropertyname(optionallyincludingaperiodcharacter),followedbyan
"="signandanotherbunchofcharactersthatrepresentsthevalue.
JakartaAnt'sonlinemanualislocatedat:http://jakarta.apache.org/ant/manual/index.html.
Hereiswhatbuild.xmldoes:
1. DefinestwotaskswithataskDefelement,calledstartandstop.Thesetaskswillbeusedbythetargetsstartandstoplateroninthebuild.xmlfile.ThesetasksallowyoutousetheTomcat"manager"application-deploymenttoolfromyourAntfiles.
Usesapropertytasktoloadinthesetofpropertiesthataredefinedintheglobal.propertiesfile.Thismeansthatthepropertynametomcat.dirisnowavailableforuselateroninthebuild.xmlfile.Thepathelementusesthetomcat.dirpropertybyincludingitsvalue(intheexample,"k:/jakarta-tomcat-4.1.12")aspartofaclasspathdefinition.Yougetthevalueoftheseimportedpropertiesbyusingareferencelike${tomcat.dir}.AnytimeyouwanttogivethepropertyadifferentvaluebeforeexecutinganAntfile,youcanjustchangethepropertiesfilebytypinginanewvalueinatexteditor.
Createsaninittargetthatechoesamessagetotheconsoleandcreatesthreeproperties(build,src,andcontext-path).Thevaluesofthesepropertiesareavailableonlyaftertheinittargethasbeenexecuted.Forexample,ifthepreparetargetdoesnothave"init"asthevalueofitsdependsattribute,thedeploy-servlettarget,whichdependsonprepare,cannotusethepropertyvaluesdefinedbyinit.
Definesatargetcalledprepare.
Buildsareusableclasspath(withtheID"classpath")outofalloftheJARfileslocatedinacoupleofTomcatdirectories.
Createsthestartandstoptargets.Thesetargetsechoamessagetotheconsoleandthencallthetasks(suchasstop)thatweredefinedwithtaskDefelementsatthetopofthebuild.xmlfile.Thestartandstoptargetsareactuallyinvokedbytheall-in-onetargetdeploy-servlet.
Createsthedeploy-servlettarget.Thistargetdoesallthemajorworkinsidethebuild.xmlfile.Noticethatitsdependsattributehasthevalue"prepare."Thismeansthatpriortoexecutingtheinstructionscontainedwithinthedeploy-servlettarget,Antfirstexecutestheinitandpreparetargets.Sincethepreparetargetdependsontheinittarget,deploy-servletcallsprepare,whichitselfcallsitowndependency,theinittarget.Sojustbylaunchingthedeploy-servlettarget,youhavetriggeredatargetchainthatlookslikeinit
prepare deploy-servlet.Usinganelementcalledantcallwithwhichatargetmayexplicitlycallanothertarget,deploy-servletcallsboththestopandstarttargets.Inthiswayitcan:
a. StopthedefaultTomcatapplication.
Compiletheservletusingthejavactask.Thejavactaskincludestheservletthatisspecifiedbythecompiled.servletproperty,whichissetinsidetheglobal.propertiesfile.
CopiesthecompiledservlettotheWEB-INF/classesdirectoryofTomcat'sdefaultwebapplication.Thecopytaskcreatesthisclassesdirectoryifitdoesnotalreadyexist.
Startsthedefaultwebapplicationsothatyoucanrequestyourservletinthebrowser.
SeeAlso
ThedeploymentsectionsofTomcat:TheDefinitiveGuide,byBrittainandDarwin(O'Reilly);Recipe2.2,Recipe2.4,andRecipe2.6;theJakartaAntonlinemanualat:http://jakarta.apache.org/ant/manual/index.html
Recipe2.2UsingaContextElementinTomcat'sserver.xml
Problem
YouwanttodeployandredeployaservletonTomcat4.1.xwithoutrestartingtheTomcatwebcontainer.
Solution
DeploytheservletaspartofaContextelementinTomcat'sserver.xmlfile.
Discussion
YoucanpastearecompiledservletclassoveranexistingservletclassandinvoketheservletwithoutrestartingTomcat:
1. LocatetheContextelementforyourwebapplicationorcreateanewContextelementinthe<tomcat-installation-directory>/conf/server.xmlfile.ContextelementsmustbenestedwithintheHostelementthatrepresentsthevirtualhostunderwhichyourwebapplicationisrunning.
SetthereloadableattributeofyourContextelementtotrue.ThissignalsTomcattomonitorthecontentsofWEB-INF/classesandWEB-INF/libforanychanges.Ifchangesaredetected,Tomcatautomaticallyreloadsthewebapplication.
TheContextelementinserver.xmllookslikethis:
<ContextclassName="org.apache.catalina.core.StandardContext"
crossContext="false"reloadable="true"
mapperClass="org.apache.catalina.core.StandardContextMapper"
useNaming="true"debug="0"swallowOutput="false"
privileged="false"displayName="HomeWebApp"
wrapperClass="org.apache.catalina.core.StandardWrapper"
docBase="h:\home"cookies="true"path="/home"
cachingAllowed="true"
charsetMapperClass="org.apache.catalina.util.CharsetMapper"
>
Thepathattributerepresentsthecontextpathfortheapplication.ThedocBaseattributepointstothedirectorythatrepresentsthetoplevelofthiswebapplication.Mostoftheexample'sotherattributeshavevaluesthataresharedbyotherContexts.Forexample,cookies="true"indicatesthattheContextwillusecookiesforthesessionidentifier,andcrossContext="false"preventstheservletsinthiswebapplicationfromobtainingrequestdispatchersforotherwebapplicationsrunninginthevirtualhost.
Settingthereloadableattributetotrueincurssignificantruntimeoverhead,sothisconfigurationisrecommendedonlyforwebapplicationsindevelopmentmode.
Underthisconfiguration,Tomcat4.1.xdisplaysaconsolemessageafteraslightdelaywhenyoupasteanewservletclassovertheoldoneinthewebapplication.Hereisanexampleofaconsolemessageinresponsetoadynamicservletreload:
WebappClassLoader:Resource'/WEB-INF/classes/com/jspservletcookbook/OracleTest.
class'wasmodified;
Dateisnow:SunFeb0222:17:41EST2003Was:SunFeb0221:38:52EST2003
SeeAlso
ThedeploymentsectionsofTomcat:TheDefinitiveGuide,byBrittainandDarwin(O'Reilly);Recipe2.1,Recipe2.4,andRecipe2.6;JakartaTomcatdocumentationfortheContextelement:http://jakarta.apache.org/tomcat/tomcat-4.1-doc/config/context.html.
Recipe2.3DeployinganIndividualServletonWebLogic
Problem
YouwanttotakeyourcompiledservletandinstallitinBEAWebLogicServer7.0tofindoutifitisworking.
Solution
CopyandpastetheclassfileintoWebLogic'sdefaultwebapplication(orintoawebapplicationthatyouhavealreadyinstalled).UsetheWebLogicAdministrationConsoletoaltertheweb.xmlfileandgivetheservletasensiblenamewithwhichtorequestitinabrowser,oruseanAntbuildfiletomovethefiletemporarilyintotheWebLogicdefaultwebapplication.
Discussion
WebLogic7.0'sdefaultwebapplicationislocatedonthefollowingpath:<WebLogic-installation-directory>/user_projects/<mydomain>/applications/DefaultWebApp.InthedefaultinstallationoftheWebLogic7.0server,notmuchexistsinthedefaultwebapplicationbutaweb.xmldeploymentdescriptor,andsomeimagefiles.Toaddaservlettothedefaultapplication,pasteyourservletclass,includingitspackage-relateddirectories,intotheDefaultWebApp/WEB-INF/classesdirectory.Youmighthavetocreateaclassesdirectorythefirsttimeyoudothis.Changetheweb.xmlfiletogivetheservletaname(whichiseasierthroughtheAdministrationConsole)beforeredeployingthewebapplicationasdescribedinRecipe2.4.
UsetheAdministrationConsoletoedittheweb.xmlfileinordertogivethenewservletaregisterednameandservlet-mappingelement.Youcanalsouseanotheravailabletool,suchasWebLogicBuilder(Recipe2.9)oratexteditor.Figure2-1showstheDefaultWebAppintheAdministrationConsole.Clickon"EditWebApplicationDeploymentDescriptors...".
Figure2-1.WebLogicServerAdministrationConsole
ThisdisplaysthescreenshowninFigure2-2.Thisscreenprovidesaneasygraphicalmethodofeditingtheweb.xmlfileforanywebapplication(inthiscase,theWebLogicdefaultwebapplication).
Figure2-2.Editingtheweb.xmlfilegraphically
Withthisgraphicaleditor,createtheservletandservlet-mappingelementsfortheservletthatyoujustadded.Makesuretoclickonthe"WebDescriptor"buttonintheleftcolumnoftheFigure2-2windowandthenpersistthechangesthatyoumadeintheweb.xmlfile.Thisactionrewritestheweb.xmlfile,addingthenewservletandservlet-mappingelements.
Nowredeploythewebapplication,whichisjustamatterofclickingafewhypertextlinksintheConsole.ChoosethenameofyourwebapplicationintheleftcolumnoftheConsole,underthemydomain Deployments
WebApplicationsnodeofthetreenavigationstructureinthislefthandcolumn.Figure2-3showstheresultingwindow.
Figure2-3.UsingtheConsoletoredeployawebapplication
Clickonthe"Deploy"tab,thenclickthe"Undeploy"buttonintheresultingHTMLtable.Thewebapplicationisnowunavailableforservice.
Toredeploytheapplication,clickthe"Deploy"tab,thenselectthe"Deploy"button,asshowninFigure2-4.
Figure2-4.Graphicallydeployingaservlet
Iftheservletthatyouareworkingonalreadyexistsinthewebapplication,thenyoucanalsocopyandpasteanewservletclassovertheoldoneintheWEB-INF/classesdirectoryofthewebapplication.Thenewservletversionbecomesavailableimmediately,withoutusingtheConsoletoredeploytheentirewebapplication.
YoucanalsouseanAntfiletocompiletheservletandcopyitintoWebLogic'sdefaultwebapplication.ThebuildfileinExample2-3isverysimilartotheoneusedanddescribedinRecipe2.1;it'sjustrevisedforusewithWebLogic'swebcontainerinsteadofTomcat's.
Example2-3.UsinganAntfilewithaWebLogicservlet
<projectname="Cookbook"default="deploy-servlet"basedir=".">
<propertyfile="wl.properties"/>
<target
name="init"
description="Initializessomeproperties.">
<echomessage="Initializingproperties."/>
<propertyname="build"value=".\build"/>
<propertyname="src"value=".\src"/>
</target>
<targetname="prepare"depends="init">
<echomessage="Cleaningupthebuilddirectory."/>
<deletedir="${build}"/>
<mkdirdir="${build}"/>
</target>
<pathid="classpath">
<filesetdir="${wl.dir}\server\lib">
<includename="*.jar"/>
</fileset>
</path>
<targetname="deploy-servlet"depends="prepare"
description="Compilethespecifiedservlet,thenmoveitinto
WL'sdefaultWebapplication.">
<echomessage="Compilingtheservlet${compiled.servlet}...."/>
<javacsrcdir="${src}"destdir="${build}">
<includename="${compiled.servlet}.java"/>
<classpathrefid="classpath"/>
</javac>
<echomessage="CopyingtheservlettoWLdefaultwebapplication..."/>
<copytodir="${wl.webapp}/WEB-INF/classes">
<filesetdir="${build}"/>
</copy>
</target>
</project>
ThisAntbuildfilefirstloadsasetofpropertiescontainedinafilecalledwl.properties,whichislocatedinthesamedirectoryasthebuildfile.Thebuildfiletypicallyhasthenamebuild.xml;however,youcancallanotherbuildfileinthesamedirectorybyusingthe-buildfilecommand-lineoption,asinant-buildfilewl_build.xml.Thewl.propertiesfileforthisexampleisshowninExample2-4.
Example2-4.wl.propertiesforWebLogicAntbuildfile
wl.webapp=k:/bea/user_projects/bwpdomain/applications/DefaultWebApp
wl.dir=k:/bea/weblogic700
compiled.servlet=test
Thedeploy-servlettargetdependsonatargetnamedpreparethatisalsodefinedinthisbuildfile.Thepreparetargetinturnhas"init"asitsdependsattribute,whichmeansthattheinittargetexecutespriortothepreparetarget.Socallingthedeploy-servlettargetcreatesa
chainofexecutingtargets:init prepare deploy-servlet.Inall,thisiswhatthebuildfileaccomplishes:
1. initcreatesacoupleofproperties(buildandsource)thatpointtodirectories.
Thepreparetargetdeletesandthenremakesthebuilddirectory,sothatyoustartwithacleanbuild.
deploy-servletcompilestheservletintothebuilddirectory,thencopiesitintothedirectoryspecifiedbythewl.webappproperty(whichcontainsitsvalueinthewl.propertiesfile).
ThepathelementcreatesaclasspathoutoftheJARfilesfoundinthek:/bea/weblogic700/server/libdirectory.ThisdirectorypathishowAntresolvesthephrase"${wl.dir}\server\lib,"whichisparsedbyattachingthevalueofthepropertywl.dirtothestring"\server\lib."
SeeAlso
Recipe2.5,Recipe2.7-Recipe2.10;thedeploymentsectionsofWebLogic:TheDefinitiveGuide,byMountjoyandChugh(O'Reilly);WebLogic'sServer7.0programmerdocumentation:http://e-docs.bea.com/wls/docs70/programming.html.
Recipe2.4DeployinganIndividualJSPonTomcat
Problem
YouwanttoplaceaJSPfileintoawebapplication.
Solution
CopytheneworrevisedJSPfileintothetop-leveldirectoryofthedefaultTomcatwebapplicationorofanotherdeployedwebapplication.
Discussion
TheeasiestwaytotestanewJSPfileistoplaceitatthetoplevelofTomcat'sdefaultwebapplication.Thisapplicationislocatedinthe<Tomcat-installation-directory>/webapps/ROOT/directory.Tomcat4.1.xcompiles(orrecompiles,ifyouarepastinganewJSPfileoveranoldone)theJSPanddisplayitsresponseinawebpage.YoudonothavetostopandstartTomcatusingtheTomcatmanagerapplicationforthenewJSPfiletobeavailabletoyourwebapplication.
PlacingaJSPfileinadeployedwebapplicationwillnotworkiftheJSPdependsonapplication-specificresourcessuchasservlets,customtags,orotherJavaclasses,becausethereisnoguaranteethatthetemporaryhostwebapplicationyouareusingfortheJSPhasaccesstothoseresources.
IfyouhavetodeployaJSPseparatelyfromitswebapplication,youcan
alsoplaceaJSPfileinadeployedwebapplicationotherthantheTomcatdefaultapplication.ThismakestheJSPpageavailabletoapplicationuserswithouthavingtostopandrestartTomcat.RememberthattheJSPfilesbelonginthetoplevelofthewebapplication,whichhasthefollowingdirectorystructure:
index.html
default.jsp
anotherJsp.jsp
images/logo.jpeg
WEB-INF/classes/jspservletcookbook/myservlet.class
WEB-INF/lib/helperclasses.jar
WEB-INF/lib/utilities.jar
WEB-INF/web.xml
WEB-INF/mytags.tld
Inotherwords,thetoplevelofthedirectorycontainstheHTMLandJSPfiles,aswellastheWEB-INFdirectory.TheWEB-INFdirectorycontains:
Theweb.xmldeploymentdescriptor
Theclassesdirectory,whichcontainspackage-relateddirectoriesandservletorsupportclasseslikeJavaBeans
Thelibdirectory,whichstoresanyJavaArchive(JAR)filescontainingutilityorhelperclassesthatyourwebapplicationuses
Optionally,anyTagLibraryDescriptorfiles(fileswith.tldsuffixes)
Anyoptionaldirectoriesforimages,videofiles,XMLfiles,orotherwebresources
SeeAlso
ThedeploymentsectionsofTomcat:TheDefinitiveGuide(O'Reilly);Recipe2.1,Recipe2.2,andRecipe2.6.
Recipe2.5DeployinganIndividualJSPonWebLogic
Problem
YouwanttoquicklytestaJSPwithoutdeployingitaspartofanewwebapplication.
Solution
CopyandpastetheJSPintothetop-leveldirectoryofBEAWebLogicServer7.0'sdefaultwebapplication,thenrequesttheJSPinabrowser.
Discussion
AJSPfilecanbe"hotdeployed"onWebLogic7.0'sdefaultwebapplicationwithouthavingtoredeploytheentirewebapplication.Thisdefaultwebapplicationislocatedat<WebLogic-installation-directory>/user_projects/<name-of-your-domain>/applications/DefaultWebApp.IfyoupasteyourJSPfileintothisdirectory(DefaultWebApp),itwillbeavailabletoreceiverequestswithoutredeployingthedefaultwebapplication.IfyourJSPfileisnamednewfile.jsp,thentheURLforrequeststothispagewouldbehttp://localhost:7001/newfile.jsp.NotetheabsenceofacontextpathorapplicationnameintheURL.Iftherequestisforthedefaultwebapplication,thentheJSPfilesappearfollowingtheforwardslash(/)afterthehost:portpartoftheURL(inotherwords,afterthelocalhost:7001/part).
Torepeatapriorcaveat:placingaJSPfileinadeployedwebapplicationinorder
totestitwillnotworkiftheJSPdependsonapplication-specificresourcessuchasservlets,customtags,orotherJavaclasses,becausethereisnoguaranteethatthetemporaryhostwebapplicationyouareusingfortheJSPhasaccesstothoseresources.
Inmostcases,theJSPisalreadypartofawebapplication,andseveraltoolsexisttoredeployawebapplication,includingAnt,BEAWebLogicBuilder,andtheWebLogicAdministrationConsole.
Finally,youcanalsocopyandpasteaJSPfileintoanotherWebLogicwebapplication.However,thatapplicationmustbedeployedinexplodeddirectoryformat,meaningthattheapplicationhasnotbeendeployedinarchiveform(asaWARorEARfile).Therefore,placetheJSPfileintheapplication'stop-leveldirectory.Iftheapplicationisnamed"newapp,"thisdirectoryisnamed<WebLogic-installation-directory>/user_projects/<name-of-your-domain>/applications/newapp.
SeeAlso
Recipe2.3;Recipe2.7-Recipe2.10;WebLogic'sServer7.0programmerdocumentation:http://e-docs.bea.com/wls/docs70/programming.html.
Recipe2.6DeployingaWebApplicationonTomcat
Problem
YouwanttodeployanentirewebapplicationonTomcat4.1.x.
Solution
CreateaJakartaAntbuildfile.Antcanautomaticallycompileyourservletclasses,createawebapplicationarchive(.war)file,thendeploytheWARtotheTomcat4.1.xserver.
Discussion
TherecommendedmethodforthecompilationanddeploymentofwebapplicationsistousetheJakartaAntautomationtool.Ifyouchangeanythingintheapplication(suchasalteringaservletorJSP),thenallittakesisasinglecommand-lineexecutionofanttocompile,package,andredeploytheapplicationonTomcat.Youdonothavetogotothetroubleofmanuallyrecompilingachangedservlet,creatinganewWARfile,startingandstoppingTomcat,andredeployingtheapplication.
AnothermethodofdeployingawebapplicationonTomcatistoplaceadirectorycontainingawebapplicationintherequireddirectorystructureintheTomcatwebappsfolder.Thenameofthewebapplicationdirectory(suchasmyapp)thenbecomesthecontextpathornameofthenewwebapplication.Thisdeploymentmethodisnotguaranteedtoworkwithotherapplicationservers,however,soitisanineffectivestrategyforcreatingportableapplications.Inaddition,sincethismanualmethodisnotautomatedinanymanner,itisawkwardtoreplaceandkeeptrackofany
changedservletorJavaBeanclassesinthesewebapplicationdirectories.
TheendofthisdiscussiondescribeshowtoconfigureTomcat'sserver.xmlconfigurationfilesothatacontextpathpointstoanunpackedwebapplicationdirectoryelsewhereontheserver.Asanalternativetocreatinganarchivedapplication(aWARfile),Tomcatdeveloperscanusethismethodofdeploymentduringdevelopmentandtesting.
UsingAntfordeployment
UsingAnttocompileanddeployanapplicationinvolvesthefollowingsteps:
1. ChooseadirectorytoholdtheAntbuild.xmlfile,anybuild.propertiesfiles,andallofthecontentsofyourwebapplication.
CreatethedirectoriestoholdtheJavaservletsourcefiles,anyJSPorHTMLfiles,JavaArchive(JAR)filesforcomponents(suchasdatabasedrivers)andthewebapplicationarchivefile(WARfile).OnewaytocreatethisdirectorystructureisshowninFigure2-5.
Figure2-5.Webapplicationdirectorystructure
3. Inthisexample,thesrcdirectorycontainstheJavasourcefilesforservletsandJavaBeans.Thewebdirectorycontainsthefiles
thatresideatthetoplevelofthewebapplication,suchasJSPandHTMLfiles.ThemetadirectoryholdsXMLdeploymentdescriptors(attheveryleast,web.xml).ThebuilddirectoryiswhereAntcompilestheJavasourcefiles.ThesefileswillendupintheWEB-INF/classesdirectoryofthewebapplication.ThelibdirectoryisforanyJARfilesthatyourwebapplicationuses,suchasdatabasedriversand/ortaglibraries.Finally,thedistdirectorycontainstheWARfile.
CreatetheJavasourcecodefortheapplicationandmoveanyotherrelatedfiles(likeJSPsandweb.xml)intotheirspecifieddirectories.
Createanynecessarypropertyvaluesinthebuild.propertiesfilethatbuild.xmlwilluseduringthecompilationanddeploymentprocess.Thesepropertieswillbedescribedinmoredetailintheupcomingdiscussion.
Runthebuild.xmlfileonthecommandlinebychangingtothedirectorycontainingthebuild.xmlfileandtypingant.
Example2-5isthebuild.propertiesfilethatisreferencedinstep5.
Thefiledoesnothavetobecalledbuild.properties;thisnameisusedpurelybyconvention.Youcouldcallitglobal.props,forinstance.
Example2-5.build.propertiesforwebapplicationdeployment
tomcat.webapps=k:/jakarta-tomcat-4.1.12/webapps/
tomcat.dir=k:/jakarta-tomcat-4.1.12
url=http://localhost:8080/manager
username=tomcat
password=tomcat
manager.path=${tomcat.dir}/work/standalone/localhost/manager
Eachofthesepropertiesismadeavailabletoorimportedintothebuild.xmlfilebythefollowinglinewithinthisfile:
<propertyfile="build.properties"/>
ThislinerepresentsapropertytaskorXMLelementwithinthebuild.xmlXMLfile.Forexample,thevalueofthetomcat.dirpropertyinsidetheAntXMLfileis"k:/jakarta-tomcat-4.1.12."
Example2-6istheentirebuild.xmlfile.ItcanbeusedtocompileJavaclasses,createaWARfile,anddeployittoTomcatjustbyexecutingantonthecommandline.ThechiefadvantageofusingAntisthatitautomatesanotherwisecomplicatedprocess.Ifyouhavetochangeoraddaservletinthewebapplication,forinstance,youcanrecompileandredeploythewebapplicationsimplybyrunningAnt.Thisbuild.xmlfileisfairlycomplexandintroducessomeadvancedfeaturesofAnt.
Example2-6.AnAntbuildfilefordeployingawebapplication
<projectname="DeployProject"default="deploy-application">
<taskdefname="deploy"classname="org.apache.catalina.ant.DeployTask"/>
<taskdefname="undeploy"classname="org.apache.catalina.ant.UndeployTask"/>
<propertyfile="build.properties"/>
<pathid="classpath">
<filesetdir="${tomcat.dir}/common/lib">
<includename="*.jar"/>
</fileset>
<filesetdir="${tomcat.dir}/common/endorsed">
<includename="*.jar"/>
</fileset>
</path>
<targetname="init"
description="Initializessomeproperties.">
<echomessage="Initializingproperties."/>
<propertyname="build"value=".\build"/>
<propertyname="src"value=".\src"/>
<propertyname="dist"value=".\dist"/>
<propertyname="lib"value=".\lib"/>
<propertyname="web"value=".\web"/>
<propertyname="meta"value=".\meta"/>
<propertyname="context-path"value="myapp"/>
</target>
<targetname="prepare"depends="init">
<echomessage="Cleaningupthebuildanddistdirectories."/>
<deletedir="${build}"/>
<mkdirdir="${build}"/>
<deletedir="${dist}"/>
<mkdirdir="${dist}"/>
</target>
<targetname="deploy"
description="DeploysaWebapplication">
<deployurl="${url}"username="${username}"password="${password}"
path="/${context-path}"war="file:${dist}/${context-path}.war"
/>
</target>
<targetname="undeploy"
description="UndeploysaWebapplication"if="already.deployed">
<undeployurl="${url}"username="${username}"password="${password}"
path="/${context-path}"/>
</target>
<targetname="create-war"description="createsawebapplicationarchivefile">
<wardestfile="${dist}/${context-path}.war"webxml="${meta}/web.xml">
<classesdir="${build}"/>
<libdir="${lib}"/>
<filesetdir="${web}"/>
</war>
</target>
<targetname="deploy-application"depends="prepare"
description="Compilethewebapplication....">
<echomessage="Undeployingtheapplicationonlyifit'sdeployed..."/>
<availablefile="${manager.path}/${context-path}.war"property="already.deployed"/>
<antcalltarget="undeploy"/>
<echomessage="Compilingtheapplicationfiles..."/>
<javacsrcdir="${src}"destdir="${build}">
<includename="*.java"/>
<classpathrefid="classpath"/>
</javac>
<echomessage="creatingtheWARfile...."/>
<antcalltarget="create-war"/>
<antcalltarget="deploy"/>
</target>
</project>
Thecreate-wartargetusesthewarAnttasktogeneratetheWARfile,basedoncertainattributevaluesandnestedelements.Forexample,theweb.xmlfilethatwillbeincludedintheWARisspecifiedasthevalueforthewartask'swebxmlattribute.Inaddition,theclassesthatwillbeincludedintheWARfile'sWEB-INF/classesdirectoryarespecifiedbythisnestedelementofthewartask:
<classesdir="${build}"/>
Thenicethingaboutthisclasseselement,alongwiththelibandfilesetnestedelements,isthatallofthenesteddirectoriesinsidethebuild,lib,andwebdirectoriesareautomaticallyincludedintheWAR.Forexample,thewebdirectoryincludesanimagesdirectorycontainingtheapplication'svariousGIFfiles.TheimagesdirectoryisincludedatthetopleveloftheWARfile,alongwithanyHTMLorJSPfilesthatarestoredin
thewebdirectory,justbyincludingthisnestedelement:
<filesetdir="${web}"/>
Alsoexaminethedeploy-applicationtarget,whichembodiesthemeatofthisbuild.xmlfile.AslongasyouproperlysetthePATHenvironmentvariabletopointattheAntcomponent,thedeploy-applicationtargetiscalledbydefaultwhenyoutypeantatthecommandline.
First,thetargetfindsoutwhetherthewebapplicationhasalreadybeendeployedonTomcat.Thisfunctionisincludedbecausethisbuildfilewillpresumablyberunoverandoveragain,notjustthefirsttimethewebapplicationisdeployed.Thislineusesanavailabletask,whichsetsapropertytothevalue"true"onlyifthefilespecifiedinitsfileattributeexists:
<availablefile="${manager.path}/${context-path}.war"
property="already.deployed"/>
<antcalltarget="undeploy"/>
Ifthisparticularfileisfound,itmeansthattheTomcatManagerapplicationhasalreadydeployedtheWARfile,andthatthealready.deployedpropertyissettotrue.Thisallowsthebuild.xmlfiletoconditionallyundeploytheapplication,beforetheapplicationisredeployedafteranychanges.Inotherwords,itundeploystheapplicationonlyifthewebapplicationisalreadydeployed(otherwise,runningtheundeploytargetraisesanerrorandhaltsexecutionofthebuildfile).Theundeploytargetrunsonlyifthealready.deployedpropertyissettotrue:
<targetname="undeploy"
description="UndeploysaWebapplication"
if="already.deployed">
Thehandyantcalltaskcallsanothertargetinthefile,similartocallingamethod.Finally,thedeploy-applicationtargetusesthejavac
tasktocompiletheapplication'sservletsintothebuilddirectory,thenusestheantcalltasktocreatetheWARfileanddeploytheneworchangedapplicationtoTomcat.Thetargetechoesvariousmessagestotheconsoletohelpindicatetothedeveloperwhatitisdoing:
<targetname="deploy-application"depends="prepare"
description="Compilethewebapplication....">
...
<echomessage="Compilingtheapplicationfiles..."/>
<javacsrcdir="${src}"destdir="${build}">
<includename="*.java"/>
<classpathrefid="classpath"/>
</javac>
<echomessage="creatingtheWARfile...."/>
<antcalltarget="create-war"/>
<antcalltarget="deploy"/>
</target>
Asanalternativetousingthepriordeploymentmethod,youcanconfigureTomcattopointtoanexternaldirectorythatcontainsavalidwebapplication.ThisstrategydeploysthewebapplicationthenexttimeTomcatisrestarted.Itisanacceptablestrategywhentheapplicationisunderdevelopment,becauseyoucanconfigureTomcattoautomaticallyreloadtheapplication(Recipe2.2)whenaservletischanged,orwhenaJARfileisaddedtoWEB-INF/lib.However,developersshoulddeployapplicationsasWARfileswhenthetimecomestoruntheapplicationonaproductionserver.
CreateafilethatcontainsaContextelementasthiselementwouldappearinserver.xml.Givethisfilea.xmlextension.Itissensibletocallthisfilethesamenameasthecontextpathorapplicationname(forexample,myapp.xml),butnotrequired.Yourfilecontentmightlooklikethis:
<ContextclassName="org.apache.catalina.core.StandardContext"
crossContext="false"reloadable="true"
mapperClass="org.apache.catalina.core.StandardContextMapper"
useNaming="true"debug="0"swallowOutput="false"
privileged="false"
wrapperClass="org.apache.catalina.core.StandardWrapper"
docBase="h:\book\cookbook\sec1\sec1_1\dist"
cookies="true"path="/newapp"cachingAllowed="true"
charsetMapperClass="org.apache.catalina.util.CharsetMapper">
</Context>
Thereloadableattributevalueof"true"configuresTomcattomonitortheclassesinWEB-INF/classesandthecomponentsinWEB-INF/libforanychanges.Tomcatautomaticallyreloadsthewebapplicationifitdetectsanychanges.
ThevalueforthedocBaseattributecanbeanabsolutepathtothedirectorythatcontainsthewebapplication,orthecontextroot.ItcanalsobethepathtoaWARfile.ThedocBaseattributecanalsobeapathnamerelativetotheappBasedirectoryoftheenclosingHostelementinserver.xml,suchasrelativetothe<Tomcat-installation-directory>/webappsdirectory.Thepathattributedeclaresthecontextpathforthenewapplication,asinhttp://localhost:8080/newapp/(where/newappisthecontextpath).
Placethisfileinthe<Tomcat-installation-directory>/webappsdirectory(orwhicheverdirectoryisconfiguredastheappBaseintheenclosingHostelementinconf/server.xml)andrestartTomcat.ThiswebapplicationcannowbeinvokedonTomcat.
SeeAlso
ThedeploymentsectionsofTomcat:TheDefinitiveGuidebyBrittainandDarwin(O'Reilly);Recipe2.1,Recipe2.2,andRecipe2.4.
Recipe2.7DeployingaWebApplicationonWebLogicUsingAnt
Problem
YouwanttodeployawebapplicationonWebLogicServer7.0usingJakartaAnt.
Solution
CreateaJakartaAntbuildfile.Antcanautomaticallycompileyourservletclasses,createaweb-applicationarchive(.war)file,andthendeploytheWARtoWebLogicServer7.0.
Discussion
YoucaneithermanuallycutandpastewebcomponentsintotheWebLogicapplicationsdirectory(asdescribedinthesidebar),oruseAnttoautomatetheprocessofcompiling,generatingaWARfile,andcopyingtheWARtothisdirectory.Anexampledirectorypathtoapplicationsisk:\bea\user_projects\bwpdomain\applications.Thismethodwouldentailaminoreditofthebuild.xmlandbuild.propertiesfilesdescribedinRecipe2.6.
ManuallyDeployingaWebApplication
WhenBEAWebLogicServer7.0isrunningindevelopmentmode,ifaWARfile,anenterprisearchiveapplication(EAR)file,oradirectorythatcontainsavalidwebapplicationisplacedintheapplicationsdirectory,thenthoseapplicationsareautomaticallydeployedandbecomeavailableontheserver.
AvalidwebapplicationcontainsaWEB-INF/web.xmldeploymentdescriptorthatdoesnotgenerateanyparsingexceptions.Ifthedirectorythatyouplaceintheapplicationsfolderdoesnotcontainadeploymentdescriptor,thenWebLogicwillnotautomaticallydeploytheapplication,eveniftheserverisrunningindevelopmentmode.WebLogicraisesanexceptionsimilartothisoneintheconsoleinwhichtheserverwasstartedup:
<Unabletoactivateapplication,_appsdir_dist_dir,fromsource,K:\bea\user_
projects\bwpdomain\applications\dist.Reason:NoJ2EEdeploymentdescriptor
foundat"K:\bea\user_projects\bwpdomain\applications\dist".>
Thisdeploy-applicationAnttargetiseditedinbuild.xmltodeployonWebLogic7.0:
<targetname="deploy-application"depends="prepare"
description="Compilethewebapplication....">
<echomessage="Compilingtheapplicationfiles..."/>
<javacsrcdir="${src}"destdir="${build}">
<includename="*.java"/>
<classpathrefid="classpath"/>
</javac>
<echomessage="creatingtheWARfile...."/>
<antcalltarget="create-war"/>
<copytodir="${wl.applications}">
<filesetdir="${dist}"/>
</copy>
</target>
Inaddition,thebuild.propertiesfilecoulddefinethewl.applicationspropertywithavaluesuchas"k:\bea\user_projects\bwpdomain\applications".OncetheWARfileiscopiedtothisspecialdirectory,aWebLogicserverthatisstartedin
developmentmodewillautomaticallydeployit.
Inthe\user_project\bwpdomaindirectory(dependingonyourserverdomainname)theWebLogicstartscriptiscalledstartWebLogic.cmdonWindowsandstartWebLogic.shonUnix.Tostarttheserverindevelopmentmode,thelineinthestartscriptshouldbesetSTARTMODE=(thevalueisanemptystringhere)orsetSTARTMODE=false.TheserverstartsinproductionmodeifitissetSTARTMODE=true.
SeeAlso
Recipe2.3;Recipe2.8-Recipe2.10;WebLogic'sServer7.0programmerdocumentation:http://e-docs.bea.com/wls/docs70/programming.html.
Recipe2.8UsingtheWebLogicAdministrationConsole
Problem
YouwanttodeployawebapplicationusingWebLogic'sAdministrationConsole.
Solution
BringuptheAdministrationConsoleinyourwebbrowseranduseitsgraphicalinterfacetodeployeitheraWARfileoraweb-applicationdirectory.
Discussion
TheWebLogicAdministrationConsoleisaservlet-andbrowser-basedtoolformanagingWebLogicserverresourcesandJava2EnterpriseEdition(J2EE)applications.TousetheConsole,WebLogicServermustberunning.First,requesttheURLhttp://localhost:7001/console(orwhicheveryourserveraddressandportis,asinhttp://<weblogic-server-address>:<port>/console).Thenenteryourloginnameandpasswordtogainentrytothebrowser-basedtool.TheresultingscreenlookslikeFigure2-6,withahierarchicallistofchoicesinthelefthandcolumnandthecurrentscreenchoiceintherighthandcolumn.
Figure2-6.WebLogicAdministrationConsole
Intheleftcolumn,choosethenameofyourdomainbyclickingontheplussign(+),whichdisplaysthedomain'ssubnodes.ThesubnodesofthedomainincludeServers,Clusters,Machines,NetworkChannels,Deployments,Services,andSecurity.Thenchoosethe"Deployments"node,whichgivesyouthechoiceofselectingits"WebApplications"subnode.Openupthe"WebApplications"nodebyclickingonitsplussign.TheresultingscreenlookslikeFigure2-7.
Figure2-7.WebApplicationsnode
IntheWebApplicationswindow,clickthe"ConfigureaNewWebApplication..."hyperlink.ThenextscreengivesyoutheoptionofuploadingtheWebApplicationArchive(WAR)orEnterpriseApplication
Archive(EAR)filethroughyourbrowsertotheserver'sfilesystem,asshowninFigure2-8.
Figure2-8.DeployingawebapplicationasaWARorEARfile
Initiatethisuploadandthenclickonthe"select"linknexttotheWARfile.CompletethethreestepsthatFigureFigure2-9shows:clickthearrowbuttonstodeploytheapplicationfromthe"AvailableServers"columntothe"TargetServers"column,nametheapplication(leavethenamethesameastheWARfilenameminusthe.warsuffix),thenpressthe"ConfigureandDeploy"button.ThatisallittakestodeploytheWARfiletothetargetserver.
Figure2-9.FinalstepsfordeployingtheWARfile
Nowtestthedeploymentbyrequestingoneoftheservletsinthebrowser,usingthenamethatyougavetheapplicationasthecontextpath.AnexampleURLishttp://localhost:7001/cookbook/cookieservlet.ThisURLrequestsaservletthathasbeenmappedtothename"/cookieservlet."Theweb-applicationcontextpathis/cookbook.
RedeployingapreviouslyundeployedwebapplicationusingtheWebLogicAdministrationConsoleinvolvesthefollowingsteps:
1. SelectthenameofyourapplicationundertheWebApplicationsnodeintheConsole'slefthandcolumn.ThisshowsascreensimilartoFigure2-10.
Figure2-10.SelectingawebapplicationintheConsole
2. Clickthe"Deploy"buttonintherighthandscreen.Thisreactivatestheapplication,sothatitcanreceiverequestsintheWebLogicwebcontainer.
IfyouwanttodeleteawebapplicationusingtheWebLogicAdministrationConsole,clickonthenameofyourdomaininthelefthandcolumnoftheConsolescreen,thenonthe"Deployments"and"WebApplications"nodes.Clickingthetrashcaniconassociatedwiththeapplication,asshowninFigure2-11,deletestheapplicationfromtheWebLogicserver.
Figure2-11.Deletingawebapplication
DeletingawebapplicationinthismannermeansthattheapplicationisnolongeravailabletoreceiverequestsintheWebLogicwebcontainer.
SeeAlso
Recipe2.3andRecipe2.7;Recipe2.9andRecipe2.10;WebLogic'sServer7.0programmerdocumentation:http://e-docs.bea.com/wls/docs70/programming.html.
Recipe2.9UsingWebLogicBuildertoDeployaWebApplication
Problem
YouwanttouseWebLogicBuildertodeployawebapplication.
Solution
WebLogicBuilderinstallswiththeWebLogic7.0Server,soyoucanlaunchtheBuilderapplicationanduseitsgraphicaltoolstodeploythewebapplication.
Discussion
WebLogicBuilderisagraphicaltoolthatinstallswithWebLogicServer7.Itcanbeusedtoeditdeploymentdescriptorfilessuchasweb.xmlandweblogic.xml,aswellasfordeployingwebapplicationstoaserver.UsingWebLogicBuilder,youcanopenup,edit,anddeploywebapplicationsthatexistaseitherWARfilesorinexplodeddirectoryformat.
Explodeddirectoryformatisaweb-applicationdirectorystructureasitwouldappearinyourfilesystem,butthatisnotinarchivedorinWARform.TobedeployedonWebLogicasawebapplication,therootdirectorymustcontaintheWEB-INF/web.xmldeploymentdescriptorandanyotherproperlystructuredapplicationcomponents,suchasatheWEB-INF/classesdirectorycontainingyourservlets(includinganypackage-relateddirectories).
YoucanlaunchWebLogicBuilderonWindowsfromeitherthe"Start"menuorthecommandline.ThestartscriptforBuilderisat:<BEA_HOME>/weblogic700/server/bin/startWLBuilder.cmd(orstartWLBuilder.shonUnix).<BEA_HOME>isthedirectorywhereWebLogicServer7.0isinstalled.
ItiseasytoopenupandeditthedeploymentdescriptorforawebapplicationinWebLogicBuilder.GototheFile OpenmenuandnavigatetotheWARfileorrootdirectoryfortheapplication.
TheresultisthewindowdepictedinFigure2-12.Thenavigationtreeintheupper-leftwindowletsyouconfigurewebresources(suchasservlets)anddeploymentdescriptorelements(suchassecurityconstraints),thensavethechangestoweb.xml.
Figure2-12.OpeningaWARfileinWebLogicBuilder
Youcanaddordeleteelementsforservlets,servletmappings,andfilters,forinstance.ThechangesarepersistedtothedeploymentdescriptorifyoumakeandsavechangestotheapplicationfromwithinWebLogicBuilder.Youcanthenoptionallyconnecttotheserverfromthe"Tools"menu,anddeploytheapplication.
The"DeployModule"windowindicateswhethertheapplicationisalreadydeployed.Figure2-13showsthiswindow.Ifyouhavealreadydeployed
theapplication,youcanstillmakedeployment-descriptorchangesinBuilder,thendeploytheapplicationagainfromthe"Tools"menu.WebLogicBuilderspecificallyundeploystheapplication,thenredeploysitwiththechangesthatyouincludedinweb.xml.
Figure2-13.WebLogicBuilder'sDeployModulewindow
WebLogicBuilderdoesnotshowanyJSPfilesthatmaybepartofthewebapplication.ItwillshowanyservletmappingsthatareassociatedwithJSPfiles.
SeeAlso
Recipe2.3,Recipe2.7,Recipe2.8,andRecipe2.10;WebLogic'sServer7.0programmerdocumentation:http://e-docs.bea.com/wls/docs70/programming.html;thelocalWebLogicBuilderHelpdocumentation:<BEA_HOME>\weblogic700\server\builder\index.html.
Recipe2.10Usingtheweblogic.DeployerCommand-LineTool
Problem
YouwanttousethecommandlinetodeployawebapplicationonWebLogicServer7.0.
Solution
UsetheJava-basedweblogic.Deployercommand-lineutility,whichisinstalledwithWebLogicServer7.0.
Discussion
Fordevelopersoradministratorswhoneedtousethecommandlineorshellscriptsfordeployingandredeployingwebapplications,WebLogicServer7.0providestheJava-basedDeployerutility.ThisutilityaccomplishesthesametasksasusingthegraphicalinterfaceoftheWebLogicAdministrationConsoletodeployorredeployawebapplication.First,thisrecipedescribeshowtodeployandredeployawebapplicationonthecommandlineusingtheDeployerutility.ThentherecipeprovidesanexampleofaWindowsbatchfilethatinvokestheDeployerutility.
TheDeployerutilitycaninitiateothertasks,suchasredeployingindividualwebcomponentsinawebapplication.TheonlinedocumentationfortheDeployerutilitycanbefoundathttp://e-docs.bea.com/wls/docs70/programming/deploying.html#1094693.
TheDeployerutilityisaJava-basedprogramthatrequiresthefollowingJARfileonyourclasspathbeforetheprogramcanrun:<BEA_HOME>\server\lib\weblogic.jar."><BEA_HOME>representsthedirectorywhereWebLogicServer7.0wasinstalled.Thefollowingcommand-linescriptonaWindowsNT4.0machineredeploysthecookbook.warwebapplicationonaservernamedbwpserver:
java-cpk:\bea\weblogic700\server\lib\weblogic.jar;
%CLASSPATH%weblogic.Deployer
-adminurlhttp://localhost:7001
-userbwperry-namecookbook-source.\dist\cookbook.war
-targetsbwpserver-activate
Thiscommand-lineinvocationdeploysthewebapplicationrepresentedbythearchivefilecookbook.war,sotheapplicationisnowavailabletoreceiverequestswiththecontextpath/cookbook.Whenrunonthecommandline,theprogrampromptstheuserforapasswordifyouhavenotincludeditinthescriptwiththe-passwordoption.The-sourceoptionspecifiesthelocationoftheWARfileorweb-applicationdirectory.The-targetsoptionspecifiesoneormoreserversonwhichtodeploythewebapplication.Thefinalcommandfordeployingtheapplicationis-activate.
Thiscommand-lineinvocationdeactivates(makesunavailable)anexistingwebapplicationontheserverbwpserver.Itpromptsfortheuserpasswordfirst,unlessyouaddthe-passwordoptiontothecommandline:
java-cpk:\bea\weblogic700\server\lib\weblogic.jar;
%CLASSPATH%weblogic.Deployer
-adminurlhttp://localhost:7001
-userbwperry-namecookbook
-targetsbwpserver-deactivate
The-cpoptionspecifiestheclasspathtouseforrunningtheDeployer
Javautility,andmustincludetheweblogic.jarJARfile.The-adminurlswitchspecifiestheadministrationserver(thedefaultvalueishttp://localhost:7001,soitdoesnothavetobeincludedhere).The-nameoptionspecifiesthenameoftheapplicationtobedeactivated,andthe-targetsoptionnamestheserverwheretheapplicationisrunning.Thefollowingcommand-lineinvocationredeploysthesame"cookbook"application:
java-cpk:\bea\weblogic700\server\lib\weblogic.jar;
%CLASSPATH%weblogic.Deployer
-userbwperry-namecookbook-activate
Thistime,the-adminurland-targetsoptionswereomitted.Thedefaultvaluesfortheseswitchesarehttp://localhost:7001andallcurrenttargets(ifthedeveloperisredeployinganexistingapplication),respectively.Iftheapplicationisbeingdeployedforthefirsttime,thedefaulttargetforthe-targetsoptionistheadministrationserver.
Itiseasiertorunshellcommandsfromabatchfile,becausethereislesstypingforcomplicatedcommand-lineprogramsandtheshellscriptscanbepermanentlysaved.Example2-7isthefirstexamplerewrittenasabatchfileonWindowsNT4.0.
Example2-7.Deployinganapplication
@echooff
setWL_HOME=K:\bea\weblogic700
setBEA_CLASSPATH=%WL_HOME%\server\lib\weblogic.jar;%CLASSPATH%
java-cp%BEA_CLASSPATH%weblogic.Deployer-adminurlhttp://localhost:7001-userbwperry
-namecookbook-source.\dist\cookbook.war-targetsbwpserver-activate
Thisbatchfilesetstwoenvironmentvariables:WL_HOMEandBEA_CLASSPATH.Theseareusedtomakesurethattheclasspathincludestheweblogic.jarfile,whichcontainstheDeployerutility.Ifthe
scriptwassavedasdeploy.bat,thisishowitwouldberunonthecommandline:
H:\book\cookbook>deploy
Theresultingconsoleoutputlookslikethis.
Enterapasswordfortheuser"bwperry":bwpserver_1968
Operationstarted,waitingfornotifications...
....
#TaskIDActionStatusTargetTypeApplicationSource
15ActivateSuccessbwpserverServercookbookH:\book\
cookbook\.\dist\cook
SeeAlso
Recipe2.3andRecipe2.5;Recipe2.7-Recipe2.9;WebLogic'sServer7.0programmerdocumentation:http://e-docs.bea.com/wls/docs70/programming.html.
Chapter3.NamingYourServletsIntroduction
Recipe3.1.MappingaServlettoaNameinweb.xml
Recipe3.2.CreatingMoreThanOneMappingtoaServlet
Recipe3.3.CreatingaJSP-TypeURLforaServlet
Recipe3.4.MappingStaticContenttoaServlet
Recipe3.5.InvokingaServletWithoutaweb.xmlMapping
Recipe3.6.MappingAllRequestsWithinaWebApplicationtoaServlet
Recipe3.7.MappingRequeststoaControllerandPreservingServletMappings
Recipe3.8.CreatingWelcomeFilesforaWebApplication
Recipe3.9.RestrictingRequestsforCertainServlets
Recipe3.10.GivingOnlytheControllerAccesstoCertainServlets
Introduction
Animportantwebapplicationconfigurationtaskistocreatethepathbywhichyourservletisrequestedbywebusers.Thisiswhattheusertypesintotheaddressfieldofhisbrowserinordertomakearequesttotheservlet.Whilethisissometimesthefullnameoftheservlet,thatconventionoftenresultsinanawkwardURI.Forexample,awebsitemighthaveaservletthatdynamicallyassemblesa"Resources"page,insteadofastaticresources.htmlpage.Usingthefullservletname,therequestURLmightbehttp://www.myorganization.com/servlet/com.organization.servlets.resources.ResourceServletThisisquiteapathtotypein;itmakesmuchmoresensetomapthistoaservletpath,whichisanaliasfortheservlet.Usingtheservletpath,the(new)addressforthedynamicpagemightbehttp://www.myorganization.com/resources.Theservletpath,inthiscase,is/resources.
ThisservletpathisalsotheidentifierusedbyotherservletsorJSPsthatforwardrequeststothisparticularservlet,aswellastheaddressthatanHTMLformtagusesinitsactionattributetolaunchparameternamesandvaluestowardtheservlet.TheservletspecificationoffersanintuitiveandflexiblewaytomapHTTPrequeststoservletsintheweb.xmldeploymentdescriptor.
Thischapterdescribeshowyoucanusetheweb.xmldeploymentdescriptortocreateoneormorealiases(servletpaths)toyourservlet.ItalsodiscusseshowtoinvoketheservletwithothertypesofURLs,suchasonethatlookslikeaJSPpagerequest(e.g.,info.jsp)oronethatlookslikeanHTMLpagerequest(info.html).Recipe3.5alsodescribeshowtoaccessaservletwithoutamappinginweb.xml,forexample,forthedeveloperwhowantstodebugherservletwithoutmodifyingtheweb.xmlfile.
Finally,Recipe3.7,Recipe3.9,andRecipe3.10showhowtomapallrequeststoone"controller"servlet(Recipe3.7),restricttherequestsforcertainservletstoauthenticatedusers(Recipe3.9),andblockall
requeststocertainservletsexceptthoseforwardedfromthecontroller(Recipe3.10).
Recipe3.1MappingaServlettoaNameinweb.xml
Problem
Youwanttocreateanalias,orservletpath,toyourservlet.
Solution
Createservletandservlet-mappingelementsinweb.xml.
Discussion
Creatinganaliastotheservlettakesplaceinthedeploymentdescriptor'sservlet-mappingelement.Allservletelementsmustcomebeforeanyoftheservlet-mappingelementsintheservlet2.3web.xmldeploymentdescriptor.Theservlet-mappingelementreferstothenameoftheservletthatappearsintheservlet-nameelement,suchas:
<servlet><servlet-name>myservlet</servlet-name></servlet>
Thisisreferredtoastheservlet'sregisteredname.Theservlet-mappingthenprovidesthename,orURLpattern,whichwebapplicationuserscantypeintotheirbrowserstoaccesstheservlet.Example3-1showsaweb.xmlfilewithaservletandservlet-mappingelement.Theregisterednameinthiscaseis"CookieServlet".
Example3-1.servletandservlet-mappingelements
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<servlet>
<servlet-name>CookieServlet</servlet-name>
<servlet-class>com.jspservletcookbook.CookieServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CookieServlet</servlet-name>
<url-pattern>/cookieservlet</url-pattern>
</servlet-mapping>
</web-app>
Inthisexample,theservletelementregistersthename"CookieServlet"byusingtheservlet-nameelement.Theclassnameisspecifiedbytheservlet-classelement.TheactuallocationofthisservletclassmaybeWEB-INF/classes/com/jspservletcookbook/,orinsideaJARfilethatresidesinWEB-INF/lib."CookieServlet"becomestheregisterednamebywhichtheservletcom.jspservletcookbook.CookieServletisreferredtointherestoftheweb.xmlfile.
Nowcreatetheservletpathbywhichthewebapplicationuserswillaccessthisservletintheirwebbrowsers.Thisaliasingisaccomplishedwiththeservlet-mappingelement.servlet-nameidentifiestheregisterednamebywhichtheservletisreferredtoinweb.xml,andtheurl-patternelementcreatestheURLthatisusedtoaccessthisservlet.The/characterinsidethe/cookieservletpatternmeans"beginattheweb-applicationroot."Forexample,ifthecontextpathforthesitehttp://www.mysite.orgis"cookbook,"thenthecompleteaddressforaccessingtheCookieServletservletishttp://www.mysite.org/cookbook/cookieservlet.The/cookbookpartofthe
URListhecontextpathforyourwebapplication.Theservletisthenidentifiedwiththe/cookieservletpatternwithinthatcontext.
Lookingatthismoregenerally,youhavethefollowingURLforanygivenservlet:
http://<host>:<port>/<contextpath>/<servlet-path>
Mostservletcontainersallowforadefaultcontext,wherethecontextpathis/.Inthiscase,theURLisinthisform:
http://<host>:<port>/<servlet-path>
Forexample,ifyouareusingTomcat4.1.xonyourlocalmachineandhavecreatedanapplicationcalled"myapp"andaservletURLpatternof/myservlet,theentirewebaddressforthatservletlookslikehttp://localhost:8080/myapp/myservlet.
YoucanalsoaccessaservletwithaURLlikethis:
http://host:port/contextpath/servlet/registered-servlet-name
Soiftheregisteredservletnamewas"MyServlet,"thentherequestappearsashttp://localhost:8080/myapp/servlet/MyServlet.
Someservletenginesuseadifferentservletpaththan/servlet,andothersallowthispathtobechangedbyanadministrator.Youshouldconsultthedocumentationforyourservletcontainertoensurethecorrectpathforyoursetup.Whatiftheexampleservlet-mappingelementappearedintheweb.xmlfilefortheserver'sdefaultwebapplication,inwhichthecontextpathis/?Inthiscase,userswouldaccesstheCookieServletservletbyusingtheaddresshttp://www.mysite.org/cookieservlet.
Theurl-patternthatyoucreateforaservletinsideofaservlet-mappingelementiscase-sensitiveinTomcatandWebLogic.AccordingtoChapterSRV.11.1oftheservletv2.3specificationandv2.4proposedfinaldraft,"The
containermustusecase-sensitivestringcomparisonsformatching."Iftheuserrequestshttp://www.mysite.org/cookbook/cookieSERVLETinsteadofhttp://www.mysite.org/cookbook/cookieservlet,thentherequestisnotdirectedtothemappedservlet(CookieServlet).InTomcat4.1.xandWebLogic7.0,therequestreturnsanHTTP404errorcode,whichisthe"Filenotfound"typeerrorreturnedbyawebserver.
Theurl-patterninsidetheservlet-mappingelementcantakeondifferentforms,whicharediscussedintheupcomingrecipes.
SeeAlso
Chapter1onweb.xml;Recipe3.2-Recipe3.8;Chapter11oftheServletv2.3and2.4specificationsonmappingrequeststoservlets.
Recipe3.2CreatingMoreThanOneMappingtoaServlet
Problem
YouwanttocreateseveralnamesorURLpatternsthatwebuserscanusetorequestasingleservlet.
Solution
Associatetheservletelementwithmorethanoneservlet-mappingelementinthedeploymentdescriptor.
Discussion
Youcancreateanumberofservlet-mappingelementsforasingleservlet,asshowninExample3-2.Ausercanaccessthisservletbyusingoneoftwoaddresses:http://www.mysite.org/cookbook/cookieservletorhttp://www.mysite.org/cookbook/mycookie.
Example3-2.Twoservlet-mappingtags
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<servlet>
<servlet-name>CookieServlet</servlet-name>
<servlet-class>com.parkerriver.cookbook.CookieServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CookieServlet</servlet-name>
<url-pattern>/cookieservlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CookieServlet</servlet-name>
<url-pattern>/mycookie</url-pattern>
</servlet-mapping>
</web-app>
Rememberthattheservlet-mappingelementshavetoappearafteralloftheservletelementsintheservlet2.3deploymentdescriptor.
OnlyexactmatchestotheURLpatternwillwork.Ifauserrequests/cookieservlet/(notethefinalforwardslash)insteadof/cookieservlet,shereceivesanHTTPerrorcodeinsteadoftheservlet-generatedpageshewasexpecting.
Youcanuseawildcardcharacter(*)toextendyourmappingpattern.ThemappingsinExample3-3invoketheCookieServletforalloftheURLsthatbeginwith/cookie/,andthenoptionallyincludeanynamesaftertheforwardslash.Forexample,CookieServletcanbeinvokedwithaURLofhttp://www.mysite.org/cookbook/cookie/youusingthisdescriptor.Thisisbecausetheurl-patternmatchesanyHTTPrequestsendingwiththe"/cookie/"string.
Example3-3.UsinganasteriskintheURLpattern
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<servlet>
<servlet-name>CookieServlet</servlet-name>
<servlet-class>com.jspservletcookbook.CookieServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CookieServlet</servlet-name>
<url-pattern>/cookie/*</url-pattern>
</servlet-mapping>
Youcannotusetheasteriskcharacterasawildcardsymbolinsidetheservlet-nameelement.Theasteriskcanbeusedonlyasawildcardsymbolintheurl-patternelement(asin<url-pattern>/cookie/*</url-pattern>),orinpatternsthatpointtoallfileswithacertainextensionorsuffix(asin<url-pattern>*.jsp</url-pattern>).Thelatterpatterniscalledanextensionmapping.
SeeAlso
Chapter1onweb.xml;Recipe3.1;Recipe3.3-Recipe3.8;Chapter11oftheServletv2.3and2.4specificationsonmappingrequeststoservlets.
Recipe3.3CreatingaJSP-TypeURLforaServlet
Problem
YouwanttolinkaURLpatternthatlookslikeaJSPfilerequesttoaservlet.
Solution
Createaservlet-mappingelementthatincludesaJSP-styleURLpattern.
Discussion
Imentionedinthepreviousrecipesthatyouhavealotoflatitudewhencreatingaliasesthatpointtoservlets.Forinstance,arequestthatappearstoaccessaJSPfilecaneasilybemappedtoaservlet.ThedeploymentdescriptorinExample3-4mapstheURLpattern/info.jsptotheJspInfoservlet.
Example3-4.DeploymentdescriptorexampleofmappingaJSP-styleURLtoaservlet
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<servlet>
<servlet-name>JspInfo</servlet-name>
<servlet-class>com.parkerriver.cookbook.JspInfo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>JspInfo</servlet-name>
<url-pattern>/info.jsp</url-pattern>
</servlet-mapping>
</web-app>
TheforwardslashthatbeginstheURLpattern/info.jspmeans"beginattherootofthewebapplicationthatusesthisdeploymentdescriptor."SotheentireURLfortheJspInfoservletlookslikethisforthecookbookwebapplication:http://www.mysite.org/cookbook/info.jsp.
YoucanalsomapallreferencestoJSPpagestoasingleservlet,asshowninExample3-5,whichusesaweb.xmlentrywithanextensionmapping.
Example3-5.MappingallJSPURLstoasingleservlet
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<servlet>
<servlet-name>JspInfo</servlet-name>
<servlet-class>com.parkerriver.cookbook.JspInfo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>JspInfo</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
</web-app>
Makesuretoexcludetheslash(/)intheURLpattern,asanextensionmappingthatusesafileextensionsuffixbeginswithanasteriskandendswithaperiodandthesuffixitself,asin<url-pattern>*.jsp</url-pattern>.ThistypeofmappingmaybeusefulifyouweremigratinganapplicationfromoneversionthatusedalotofJSPpagestoanewversionthatreliedentirelyonservlets.ThistakescareofuserswhohavebookmarkedmanyURLsthatinvolveJSPfiles.
Tomcat4.1.xincludesanimplicitmappingtoitsownJSPpagecompilerandexecutionservletforanyrequestendingin.jsp.Ifyouincludeamappingsuchastheoneinthepreviousweb-appfragment,thenyourmappingwilloverrideTomcat'simplicitmapping.
SeeAlso
Chapter1onweb.xml;Recipe3.1andRecipe3.2;Recipe3.4-Recipe3.8;Chapter11oftheServletv2.3and2.4specificationsonmappingrequeststoservlets.
Recipe3.4MappingStaticContenttoaServlet
Problem
YouwantrequestsforstaticcontentsuchasHTML-styleURLstorequestaservlet.
Solution
Useaservlet-mappingelementinweb.xmltomaptheservletnametothestaticcontent.
Discussion
Itoftenseemsoddtothecasualprogrammer,butyoucanhaveaservletrespondtoaURLthatappearstobestaticcontent,suchasanHTMLfile.Example3-6mapstheservletHtmlServlettoallURLsendinginthe.htmlsuffix.Anyrequestwithinthewebapplicationthatcontainsthisdeploymentdescriptorandspecifiesafileendingwith.htmlisdirectedtoHtmlServlet.
Example3-6.Mappingstaticcontenttoaservletinweb.xml
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<servlet>
<servlet-name>HtmlServlet</servlet-name>
<servlet-class>com.jspservletcookbook.HtmlServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HtmlServlet</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
Theservlet-mappingelementinthislistingcontainsanextension-mappingURLpattern:itbeginswithanasteriskandendswith.html.IfyouwanttomaptheservlettojustoneHTMLfile,useXMLthatlookslikethis:
<url-pattern>myfile.html</url-pattern>.
Usingthispattern,onlyrequestsforthemyfile.htmlfilearedirectedtoHtmlServlet.
MakesurethatURLpatternsneverbeginwithaslash(/)whenyouarecreatingextensionmappings.
SeeAlso
Chapter1onweb.xml;Recipe3.3;Recipe3.5-Recipe3.8;Chapter11oftheServletv2.3and2.4specificationsonmappingrequeststoservlets.
Recipe3.5InvokingaServletWithoutaweb.xmlMapping
Problem
Youwanttorequestaservletthatdoesnothaveaservlet-mappingelementintheweb.xmldeploymentdescriptor.
Solution
Useaninvoker-styleURLoftheformhttp://www.mysite.org/mywebapp/servlet/com.jspservletcookbook.MyServlet
Discussion
Someservletsmaynothaveapathmappinginthewebapplication'sdeploymentdescriptor.Sohowcanauserrequestthisservlet?WhatnameandURLdotheyuse?
Tomcatandotherservletcontainersprovideamethodforinvokingservletsthatarenotmappedinweb.xml.YoucanuseaURLofthefollowingform:
http://www.mysite.org/mywebapp/servlet/<fullyqualifiedclassnameofservlet>
Aservletwiththeclassandpackagenameofjspservletcookbook.MyServletisinvokedashttp://www.mysite.org/mywebapp/servlet/jspservletcookbook.MyServlet.Ensurethatthepathsegmentfollowingthenameofyourwebapplicationis/servlet/andnot/servlets/.Iftheservletisstoredinthedefaultwebapplication(generallyatthetopleveloftheservletcontainer),theURL
forinvokingitishttp://www.mysite.org/servlet/jspservletcookbook.MyServlet.
Theweb.xmlfilelocatedin<Tomcat_install_directory>/confincludesthisdefinitionandmappingfortheinvokerservlet:
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>org.apache.catalina.servlets.InvokerServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
Theinvokerservletcanalsobeusedtoinvoketheservletsthatareregisteredinweb.xml.TheseURLslooklikehttp://www.mysite.org/cookbook/servlet/<RegisteredServletName>.Forinstance,imagineyouhaveaservletelementlikethis:
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>jspservletcookbook.MyServlet</servlet-class>
</servlet>
Considerthatthewebapplicationcontextpathis/cookbook.IftheTomcatinvokerservletisenabledinthisapplication,thenthisservletcanbeinvokedwithitsregisterednameathttp://www.mysite.org/cookbook/servlet/myservlet.
InTomcat4.1.x,theinvokerservletmappingmaybecommentedoutinsideofthe
<tomcat-installation-directory>/conf/web.xmlfile.Thepurposeofthusdisablingtheinvokeristoensurethatservletscanbeinvokedusingonlythepathsspecifiedbytheservlet-mappingelementsinweb.xml.
Ifaservletisrequestedusingtheformhttp://www.mysite.org/myapp/servlet/<fully-qualified-classname>,ratherthanusingtheservlet'sregisteredname,anyinitializationparametersprovidedforthatservletintheweb.xmlfilearenotavailable.Example3-7showsaregisteredservletwithinitparameters.
Example3-7.Aregisteredservletwithinitparameters
<servlet>
<servlet-name>Weather</servlet-name>
<servlet-class>home.Weather</servlet-class>
<init-param>
<param-name>region</param-name>
<param-value>NewEngland</param-value>
</init-param>
</servlet>
Becauseitistheregisterednameoftheservletthathastheregionparameterassignedtoit,onlyarequestforthatregisteredname(oraservletpathmappedtothatname)triggerstheregionparameters.AccessingtheservletthroughitsfullyqualifiednamewillnotresultintheregionparameterbeingpassedtotheWeatherservlet.
SeeAlso
Chapter1onweb.xml;Recipe3.1-Recipe3.4;Recipe3.6-Recipe3.8;Chapter11oftheServletv2.3and2.4specificationsonmappingrequeststoservlets.
Recipe3.6MappingAllRequestsWithinaWebApplicationtoaServlet
Problem
Youwanttohaveallwebapplicationrequestsgotoasinglecontrollerservlet.
Solution
Useaservlet-mappingelementinyourdeploymentdescriptor,withaurl-patternelementof<url-pattern>/*</url-pattern>.
Discussion
Insomecases,youmightwanttohaveallrequestsrelatedtothewebapplicationtogoasingleservlet.Thisservletcontrollermaylogrequests,implementsecurity,orexamineandoptionallyaltertherequestobjectbeforeitforwardstherequesttoanotherlocation(usuallyanotherservletorJSP).
FortheSunMicrosystemsdescriptionoftheFrontControllerdesignpattern,whichisamethodforusingaservletasacentralprocessingpoint,seetheCoreJ2EEBlueprintspageathttp://java.sun.com/blueprints/corej2eepatterns/Patterns/FrontController.html.
Onceagain,web.xmlistheplacetoconfigureaservlettoreceiveallweb
applicationrequests.Example3-8showshowtouseaURLpatterntoaimallrequestsatacontrollerservlet.
Example3-8.Aimingallrequestsatacontrollerservlet
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<servlet>
<servlet-name>Interceptor</servlet-name>
<servlet-class>com.jspservletcookbook.Interceptor</servlet-class>
</servlet>
<!--ThemappingsfortheInterceptorservlet-->
<servlet-mapping>
<servlet-name>Interceptor</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Interceptor</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
</web-app>
Youmayalsohavetooverrideanydefaultinvokerservletwithyourownmapping:
<url-pattern>/servlet/*</url-pattern>
Maptheservletthatyouwanttoreceiveallwebapplicationrequeststo
thisURLpatternaswell.Ifyoukeeptheinvokerservletthewayitis,userscouldbypassthecontrollerservletbyusingaURLlikehttp://www.mysite.org/myapp/servlet/com.jspservletcookbook.CookieServlet
InTomcat,youcanalsodisabletheinvokerservletinthetop-levelweb.xmlfile(in<Tomcat_install_directory>/conf)bycommentingouttheservlet-mappingelement.ThisaffectsallotherwebapplicationsrunningunderthatTomcatinstance,however,sothisdecisionshouldbemadecollectivelyamongadministratorswhodeployapplicationsonthatserver.
Youmustalsoremove,alter,orcommentoutotherservlet-mappingelementsthatallowservletrequeststobypassthecontrollerservlet.Ifamorespecificmapping(suchastheoneinExample3-9)isincludedinweb.xml,requestsfortheCookieServletwillbypasstheInterceptorservlet.
Example3-9.Specificmappingsoverridemappingsusingwildcardsymbols
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<servlet>
<servlet-name>Interceptor</servlet-name>
<servlet-class>jspservletcookbook.Interceptor</servlet-class>
</servlet>
<servlet>
<servlet-name>CookieServlet</servlet-name>
<servlet-class>
com.jspservletcookbook.CookieServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Interceptor</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CookieServlet</servlet-name>
<url-pattern>/CookieServlet</url-pattern>
</servlet-mapping>
</web-app>
Theservlet-mappingelementforCookieServletinthisexamplewouldcausetheservletpathof/CookieServlettobypasstheInterceptorservlet,becausetheservletpathof/CookieServlet(aspartofarequestthatlookslikehttp://host:port/context-path/CookieServlet)isamoreexactmatchtotheURLpatternof/CookieServletthanitisto/*.
Therequestsforstaticcontentsuchaswelcomefiles(e.g.,index.html)arealsointerceptedbytheURLpattern/*.Therequestsforthesestaticfileswillalsogotothecontrollerservlet.
SeeAlso
Chapter1onweb.xml;Recipe3.1-Recipe3.4;Recipe3.6-Recipe3.8;
Chapter11oftheServletv2.3and2.4specificationsonmappingrequeststoservlets;theCoreJ2EEBlueprintspage:http://java.sun.com/blueprints/corej2eepatterns/Patterns/FrontController.html
Recipe3.7MappingRequeststoaControllerandPreservingServletMappings
Problem
Youwanttomapallrequeststoasinglecontrollerservlet,whilepreservingtheservletmappingsforotherservletsinasecuremanner.
Solution
Usesecurity-constraintelementsinweb.xmltopreventwebusersfrommakingrequeststothenoncontrollerservlets.
Discussion
Whatifthecontrollerservletthatreceivesallrequestswantstoconditionallyforwardtherequestalongtoanotherservletforspecializedprocessing?Ifalloftheotherservletmappingsareremovedfromweb.xmlandtheinvoker-styleURLpattern(/servlet/*)ismappedtothecontrollerservletitself,eventhecontrollerservletispreventedfromforwardingarequesttoanotherservlet!Howcanyougetaroundtheserestrictions?
Asolutionistoretaintheindividualservletmappingsinweb.xml.Thenyoucanusesecurity-constraintelementstopreventwebusersfrommakingrequeststothesenoncontrollerservlets.Whenthecontrollerservletwantstoforwardarequesttoanotherservlet,itusesanobjectthatimplementsthejavax.servlet.RequestDispatcherinterface.RequestDispatchersarenotrestrictedfromforwardingrequests(usingtheRequestDispatcher.forward(request,response)
method)toURLpatternsthatarespecifiedbysecurity-constraintelements.Example3-10showsaservletnamedControllerthatusesaRequestDispatchertoforwardarequesttoanotherservlet.
Recipe3.9describeshowtoprotectservletsfromreceivinganyweb-userrequestswiththesecurity-constraintelement,soIwon'trepeatthatinformationhere.
Example3-10.UsingRequestDispatchertoforwardarequest
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassControllerextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
RequestDispatcherdispatcher=null;
Stringparam=request.getParameter("go");
if(param==null)
thrownewServletException("MissingparameterinController.");
elseif(param.equals("weather"))
dispatcher=request.getRequestDispatcher("/weather");
elseif(param.equals("maps"))
dispatcher=request.getRequestDispatcher("/maps");
else
thrownewServletException(
"ImproperparameterpassedtoController.");
//ifwegetthisfar,dispatchtherequesttothecorrectURL
if(dispatcher!=null)
dispatcher.forward(request,response);
else
thrownewServletException(
"Controllerreceivedanulldispatcherfromrequestobject.");
}
}
Theservletchecksthegoparameterforitsvalue.Arequesttothisservletmightlooklike:
http://localhost:8080/home?go=weather
Inthisexample,theControllerservletismappedtoreceiveallwebrequeststothe"home"webapplication.Inotherwords,thecontroller'sservlet-mappinginweb.xmlhasaurl-patternof/*.
Basedonthegoparametervalue,ControllercreatesaRequestDispatcherobjectwithadifferentspecifiedURLforforwarding.TheservletgetsaRequestDispatcherobjectfirstbycallingtherequestobject'sgetRequestDispatcher(Stringpath)method.Thepathparametercanberelativetothecontextrootofthewebapplication,asitishere,butitcannotextendbeyondthecurrentservletcontext.SupposetheURLpattern/weatherismappedtotheregisteredservletname"Weather":
<servlet-mapping>
<servlet-name>Weather</servlet-name>
<url-pattern>/weather</url-pattern>
</servlet-mapping>
Inthiscase,thepathpassedtothegetRequestDispatcher()methodlookslikegetRequestDispatcher("/weather").Ifthegoparameteriseitherwrongormissing,theControllerthrowsaServletExceptionwithanappropriatemessage.TheWeatherservlet,though,cannotbeaccessedbywebusersdirectlybecauseitisrestrictedbyasecurity-constraintelementbuttheRequestDispatcher.forward(request,response)methodisnotlimitedbytheseconstraints.
Youcanalsousethejavax.servlet.ServletContext.getNamedDispatcher(String
name)methodtogetaRequestDispatcherobjectforforwarding.Usingthismethod,youdonothavetoincludeanyservlet-mappingelementsforthetargetservlet.ThegetNamedDispatcher()methodtakesasitsparametertheregisterednameoftheservletinweb.xml.Example3-11showsthepriorservletexamplealteredtousegetNamedDispatcher("Weather"),usingtheweatherservlet'sregisterednameinstead.
Example3-11.UsinggetNamedDispatcher()toforwardarequest
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassControllerextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
RequestDispatcherdispatcher=null;
Stringparam=request.getParameter("go");
if(param==null)
thrownew
ServletException("MissingparameterinController.");
elseif(param.equals("weather"))
dispatcher=getServletContext().
getNamedDispatcher("Weather");
elseif(param.equals("maps"))
dispatcher=getServletContext().
getNamedDispatcher("Maps");
else
thrownewServletException(
"ImproperparameterpassedtoController.");
/*checkforanulldispatcher,then
dispatchtherequesttothecorrectURL*/
if(dispatcher!=null)
dispatcher.forward(request,response);
else
thrownewServletException(
"Controllerreceivedanulldispatcher.");
}
}
ThedoGet()methodhasbeenchangedtouseaRequestDispatcherreceivedfromtheServletContext.getNamedDispatcher(Stringregistered-servlet-name)method.Insteadofaservletpath,thedispatcherobjectusesthatservlet'sregisteredname("Weather")fromweb.xml,asin:
<servlet>
<servlet-name>Weather</servlet-name>
<servlet-class>com.jspservletcookbook.Weather
</servlet-class>
</servlet>
IftheServletContextreturnsanulldispatcherbecausesomeoneleftoutthenecessaryXMLelementinweb.xml,thendoGet()throwsaServletExceptionexplainingthatthedispatcherobjectisnull.
Analternatestrategyistousealistenertochecktherequestbeforeitfindsitswaytoaservlet.Chapter19describeshowtousealistenertoexamineanHTTPrequest.
SeeAlso
Chapter1onweb.xml;Recipe3.1-Recipe3.5;Recipe3.8;Chapter19onusingalistenertoexaminetherequest;Chapter11oftheServletv2.3and2.4specificationsonmappingrequeststoservlets;theCoreJ2EEBlueprintspage:http://java.sun.com/blueprints/corej2eepatterns/Patterns/FrontController.html
Recipe3.8CreatingWelcomeFilesforaWebApplication
Problem
Youwanttoconfigureoneormorewelcomefilesforawebapplication.
Solution
Useawelcome-file-listelementinyourdeploymentdescriptor.
Discussion
AwelcomefileisatraditionasoldasthehypertextualInternet.Manysiteshavehomepagesorotherwelcomefilesthataredesignedtobetheentrypageorfrontdoorfortheirwebsites.Thesepagesusuallyhavenameslikeindex.html,welcome.html,ordefault.html.Youcanconfigureyourwebapplicationtodirectrequeststowardthesepagesbyaddingawelcome-file-listelementtoyourwebapplication'sdeploymentdescriptor.Setupawelcomefilelistinweb.xmlinthemannerdemonstratedbyExample3-12.Thewelcome-file-listelementmustcomeafteranyservletandservlet-mappingelements,andprecedeanyerror-pageortaglibelementsintheservlet2.3deploymentdescriptor.
Example3-12.Settingupwelcomefilesinweb.xml
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<!--Defineservletsandservlet-mappingshere-->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
WhenevertheservletcontainerencountersaURLforawebapplicationthatspecifiesonlyadirectory,notaparticularfilenameorservlet,thenitlooksforawelcome-file-listelementintheapplication'sdeploymentdescriptor.Theservletv2.3specificationcallsthesekindsofURLsvalidpartialrequests.Theservletcontainerattachesanywelcomefilenamesthatitfindsinweb.xmltotherequest(intheorderthattheyappearinweb.xml)andreturnsthosefilestotheclient.
Forexample,let'ssayTomcatreceivesarequestforhttp://www.mysite.org/cookbook/.Alsoimaginethattheweb.xmlfileforthecookbookwebapplicationcontainsthewelcome-file-listshowninExample3-12.Tomcatthenreturnshttp://www.mysite.org/cookbook/index.htmlifthatfileexists;ifitdoesnot,Tomcatlooksforthedefault.jspfileinthecookbookdirectoryandreturnsthatfileinstead.
Theservletcontainerinitiatesthissearchinresponsetoanydirectory-styleURLthatitreceives(suchashttp://www.mysite.org/cookbook/bookinfo/).Inotherwords,aslongasanindex.htmlordefault.jsp(orwhicheverfilenamesyouchoose)existsinawebapplication'srootdirectory,andthewebdeveloperhasproperlyconfiguredthewelcome-file-listelement,thenthosefilesare
invokedbydefaultinresponsetodirectory-stylerequests.
SeeAlso
Chapter1onweb.xml;Recipe3.1-Recipe3.6;Recipe3.9;Chapter11oftheServletv2.3and2.4specificationsonmappingrequeststoservlets.
Recipe3.9RestrictingRequestsforCertainServlets
Problem
Youwanttoallowonlyauthenticateduserstorequestcertainservlets.
Solution
Usethesecurity-constraintelementintheweb.xmldeploymentdescriptor.
Discussion
Somewebapplicationscontainservletsthatshouldnotbeinvokeddirectlybywebusers,becausetheyhandlesensitivedataandmayhavespecialjobs(suchasadministeringtheserverorwebapplication).Forexample,youcoulddesignaservletthatisaccessedonlybyserveradministrators.Howdoyouprotecttheseservletsfrombeinginvokedimproperlyorbyunauthorizedusers?
Inthelattercase,youcanusedeclarativesecurity,orcontainer-managedsecurity.Thisstrategyinvolvesconfiguringtheweb.xmldeploymentdescriptorwithyourapplication'ssecurityinformation,therebydecouplingsecurityinformationfromyourservlet'scode.AnysecuritychangesforawebapplicationcanthenbemadeintheXMLconfigurationfiles(orviatheWebLogicServer7.0AdministrationConsole)withoutmessingwiththeservlet'ssourcecode.Thesecurityconfigurationisthenloadedandimplementedbytheservletcontainer.
Youcanalsouseprogrammaticsecurity,whichinvolvesincluding
security-relatedcodewithinservlets,suchascheckingtheHttpServletRequestobjecttoseeifauserisauthorizedtouseacertainwebresource.
ForTomcat,usingthesecurity-constraintelementinweb.xmlrequirescreatingausernameandpasswordintheXMLfilelocatedat<Tomcat-installation-directory>/conf/tomcat-users.xml.ThisisanXMLfileinwhichyoudefineinternalusersandpasswords.ItmightlooklikeExample3-13.
Example3-13.Atomcat-users.xmlfile
<?xmlversion='1.0'encoding='utf-8'?>
<tomcat-users>
<rolerolename="manager"/>
<rolerolename="tomcat"/>
<rolerolename="developer"/>
<userusername="tomcat"password="tomcat"roles="tomcat,manager"/>
<userusername="bruce"password="bruce1957"
roles="tomcat,manager,developer"/>
<userusername="stacy"password="stacy1986"roles="tomcat"/>
</tomcat-users>
ThisXMLfragmentincludesatomcat-usersrootelementcontainingoneormoreroleanduserelements,dependingonhowmanyusersaredefinedforthewebapplicationshandledbythatinstanceofTomcat.Thistomcat-users.xmlconfigurationfileisaccessiblebyallofthecontainedwebapplications.
Youthencreatesecurity-constraint,login-config,andsecurity-roleelementsinsideofthewebapplication'sdeploymentdescriptor,orweb.xml.
Ifyouarenotusingtheservletv2.4deploymentdescriptor,thesecurity-relatedelementshavetoappearinthisorderandfollowmostoftheotherelementsthatcanappearinweb.xml,oryourdeploymentdescriptorwillnotbeavalidXMLfile.
Specifically,theonlyelementsthatcancomeaftersecurity-roleareenv-entry,ejb-ref,andejb-local-ref.
Thesecurity-constraintelementlookslikeExample3-14,giventhattheprotectedURLpatterninthiscaseis<url-pattern>/CookieServlet</url-pattern>.
Example3-14.Thesecurity-constraintelement
<security-constraint>
<web-resource-collection>
<web-resource-name>CookieInfo</web-resource-name>
<url-pattern>/CookieServlet</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description>Thisappliesonlytothe
"developer"securityrole</description>
<role-name>developer</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
Thesecurity-constraintelementmustcontainoneormoreweb-resource-collectionelements.Theweb-resource-collectionelementdescribeswhichwebresourcesinthewebapplicationareprotectedbythespecifiedsecurityconstraint.Inotherwords,arequestovertheInternetforawebresource,suchasaservlet,triggersanysecurityconstraintthathasbeenmappedtotheresource.Inthisexample,thesecurityconstraintprotectsanyrequestthatfitstheURL
pattern,<web-application-root-directory>/CookieServlet.Thehttp-methodelementsspecifytheHTTPmethodsthatthissecurityconstraintcovers.Intheexample,aGETorPOSTrequestfor/CookieServlettriggerstheconfiguredsecuritymechanism.Ifyoudonotincludeanyhttp-methodelementsunderthesecurity-constraintelement,theconstraintwillapplytoanyHTTPmethod(suchasPUTorDELETE,inadditiontoGETandPOST).
Theobjectsthatimplementthejavax.servlet.RequestDispatcherinterfacemayforwardHTTPrequestsfromoneservlettoaprotectedservletwithouttriggeringthesesecurityconstraints.
Theauth-constraintelementisdesignedtodescribethesecurityrolesthatpermitaccesstothewebcomponent.Asecurityroleisanamethatrepresentsthesecurityprivilegesauserorgroupofusershaveinrelationtoaparticularresource,suchasaservlet.Examplesofsecurityrolesareadmin,manager,ordeveloper.Inthecaseofthetomcat-users.xmlfile,usersareassignedtoroles.Withinthesecurity-constraintelementexample,onlyusersthataremappedtothedeveloperroleinthetomcat-users.xmlfilehaveaccesstoCookieServlet.
Howdoesawebapplicationauthenticateauserinthefirstplace?Forinstance,howcanthewebapplicationfindouttherequester'susernameandpassword,andtherebydetermineifhecanbegivenaccesstotheservlet?Incontainer-managedsecurity,thisiswhatthelogin-configelementisusedfor.Thiselementappearsafterthesecurity-constraintelementintheweb.xmlfile.BothelementsmightlooklikeExample3-15inawebapplication'sdeploymentdescriptor.
Example3-15.Usinglogin-configwithasecurity-constraintelement
<security-constraint>
<web-resource-collection>
<web-resource-name>CookieInfo</web-resource-name>
<url-pattern>/CookieServlet</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description>Thisappliesonlytothe
"developer"securityrole</description>
<role-name>developer</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>developer</role-name>
</security-role>
Thelogin-configelementspecifiestheauthenticationmethodthatisusedtoauthenticateanyuserrequestsforprotectedwebresources.Protectedwebresourcesarethosespecifiedbyaweb-resource-collectionelement,insidethesecurity-constraintelement.Intheexample,BASICauthenticationisusedforanyrequeststhatmatchtheURLpattern/CookieServlet.BASICisafamiliarformofwebauthenticationinwhichthebrowserpresentstheuserwithadialogwindowforenteringtheusernameandpassword.Tomcatcomparesthegivennameandpasswordwiththeuserinformationconfiguredinthetomcat-users.xmlfile,andthenusesthewebapplication'ssecurity-constraintconfigurationtodeterminewhethertheusercanaccesstheprotectedservlet.
Theauth-methodchildelementoflogin-configcanalsobegiventhevaluesFORM,CLIENT-CERT,orDIGEST.
Onemoreingredientisnecessarytocompletethisservletsecurityconfiguration:thesecurity-roleelement.Example3-15createsasecurityrolenameddeveloper.Thedevelopervaluealsoappearsinthesecurity-constraintchildelementauth-constraint.Thismeansthatonlyuserswhoaremappedtothesecurityroledeveloperareabletoaccesswebresourceswhichareprotectedbythesecurityconstraint(i.e.,thatareidentifiedbyaweb-resource-collectionchildelementofsecurity-constraint).Inotherwords,thisauthenticationmethodisactuallyatwo-stepprocess:
1. Checkiftheprovidedusernameandpasswordarecorrect.
Determineiftheuserismappedtothespecifiedsecurityrole.Forexample,theusermightprovideacorrectusernameandpassword,butshemaynotbemappedtothespecifiedsecurityrole.Inthiscase,sheispreventedfromaccessingthespecifiedwebresource.
TheusersaremappedtosecurityrolesinTomcatinthepreviouslymentionedtomcat-users.xmlfile.Hereisanexampleofwhatauserelementmightlooklikeinthetomcat-users.xmlfile:
<username="bwperry"password="bruce2002"
roles="developer,standard,manager"/>
Thisuserisassignedthreedifferentroles:developer,standard,andmanager.TheTomcatservletcontainerusestheseXMLelementsinthetomcat-users.xmlfiletodeterminewhethercertainusername/passwordcombinationshavebeenassignedparticularroles.Figure3-1isdesignedtounraveltheseconfusingcross-references.Justthinkofasecurityroleasawaytofurtherrefineagroupofapplicationusers,orgroupthemintermsoftheiruserprivileges.
Figure3-1.Usingasecurityconstraintelement
ThesecurityconfigurationdepictedbyExample3-15sXMLtextcanbeusedwithWebLogic7.0,buttheWebLogic-specificconfigurationfileiscalledweblogic.xml.
Theweblogic.xmlfileaccompaniestheweb.xmldeploymentdescriptorinsideyourwebapplication'sWEB-INFdirectory.
Example3-16showstheXMLwithintheweblogic.xmldeploymentdescriptor.
Example3-16.Securityroleinweblogic.xml
<!--weblogic.xmlsecurityrolemapping-->
<security-role-assignment>
<role-name>developer</role-name>
<principal-name>bwperry</principal-name>
</security-role-assignment>
InWebLogic7.0,youcanalsoestablishusers,groups,andsecurityrolesthatareglobaltoaparticularWebLogicserverthroughtheAdministrativeConsole.
Thisrecipedescribedhowtorestricttherequestsforcertainservlets.Thenextrecipeshowsonewaytopreventallrequestsexceptthoseforwardedfromacontrollerservletfromreachingotherservlets.
SeeAlso
Chapter1onweb.xml;Recipe3.1-Recipe3.8;Chapter11oftheServletv2.3and2.4specificationsonmappingrequeststoservlets;theCoreJ2EEBlueprintspage:http://java.sun.com/blueprints/corej2eepatterns/Patterns/FrontController.html
Recipe3.10GivingOnlytheControllerAccesstoCertainServlets
Problem
Youwanttosetupthewebapplicationsothatonlyacontrollerservlethasaccesstocertainservlets.
Solution
Createasecurity-rolethatdoesnothaveanyusersmappedtoit,thenspecifyinthesecurity-constraintelementtheservletsthatyouwanttopreserveforthecontroller.
Discussion
Thisrecipeshowshowyoucancreateasecurity-constraintelementthatforbidsanyrequestsfromreachingspecifiedURLpatterns.
TheservletsmappedtothoseURLpatternsareforwardedrequestsonlyfromoneormorecontrollerservletsthatuseanobjectthatimplementsthejavax.servlet.RequestDispatcherinterface.Recipe3.7includesanexamplecontrollerservletthatforwardsarequesttoanotherservletusingaRequestDispatcher.Example3-17showshowyoucansetupthesecurity-constraintelementforanexampleservletwiththeregisteredname"Weather".
Example3-17.Asecurity-constraintthatallowsonlyRequestDispatcher.forward-relatedrequests
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd">
<web-app>
<!--configuretheWeatherservlet;
itreceivesrequestsfroma
controllerservlet-->
<servlet>
<servlet-name>Weather</servlet-name>
<servlet-class>
com.jspservletcookbook.Weather
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Weather</servlet-name>
<url-pattern>/weatherurl-pattern>
</servlet-mapping>
<!--thiselementpreventstheWeatherservlet
fromdirectlyreceivingrequestsfromusers,
becausenousersaremappedtothe'nullrole'role-->
<security-constraint>
<web-resource-collection>
<web-resource-name>Weather
</web-resource-name>
<url-pattern>/weather</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>nullrole</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE
</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>nullrole</role-name>
</security-role>
</web-app>
ThenextstepinprotectingtheWeatherservletistomakesurethatthetomcat-users.xmlfiledoesnotmapanyuserstothe"nullrole"securityrole.Thesecurity-roleelementlookslikethis:
<security-role>
<role-name>nullrole</role-name>
</security-role>
Hereiswhatatypical<Tomcat-installation-directory>/conf/tomcat-users.xmlfilelookslike:
<?xmlversion='1.0'encoding='utf-8'?>
<tomcat-users>
<rolerolename="manager"/>
<rolerolename="tomcat"/>
<rolerolename="developer"/>
<userusername="tomcat"password="tomcat"roles="tomcat,manager"/>
<userusername="bruce"password="bruce1957"
roles="tomcat,manager,developer"/>
</tomcat-users>
InwebapplicationsconfiguredinthemannerofExample3-17,anydirectrequesttotheURLpattern/weatherreceivesaresponseinthecategoryof"HTTPStatus403Accesstotherequestedresourcehasbeendenied."However,acontrollerservletcanstillusetheRequestDispatcher.forward(request,response)methodtoforwardarequesttothe/weatherURLforprocessing.Recipe3.7andExample3-10showaservletthatusesthisforwardmethod,soIwon't
repeatthatcodehere.
Makesuretoconfigurefriendlyerrorpagesfortheuserswhomakerequeststorestrictedservlets.Chapter9describeshowtodesignateerrorpagesforcertainHTTPresponsecodesinthewebapplication'sdeploymentdescriptor.Youmaywanttoprovideautomaticrefreshesafteraspecifiedintervalfromtheerrorpagetothecontrolleroranyloginpages.
SeeAlso
Chapter1onweb.xml;Recipe3.1-Recipe3.9;Chapter11oftheServletv2.3and2.4specificationsonmappingrequeststoservlets;theCoreJ2EEBlueprintspage:http://java.sun.com/blueprints/corej2eepatterns/Patterns/FrontController.html
Chapter4.UsingApacheAnt
Introduction
Recipe4.1.ObtainingandSettingUpAnt
Recipe4.2.UsingAntTargets
Recipe4.3.IncludingTomcatJARfilesintheBuildFileClasspath
Recipe4.4.CompilingaServletwithanAntBuildFile
Recipe4.5.CreatingaWARFilewithAnt
Recipe4.6.CreatingaJARFilewithAnt
Recipe4.7.StartingaTomcatApplicationwithAnt
Recipe4.8.StoppingaTomcatApplicationwithAnt
Introduction
ApacheAnt(http://ant.apache.org/)isaJava-andXML-basedautomationtoolthatisavailableasopensourcesoftwarefromtheApacheSoftwareFoundation.AntbeganitslifeaspartoftheTomcatcodebase.Thetool'sfirstofficialreleaseasastandalonesoftwareproductwasinJuly2000,accordingtotheAntFAQ(http://ant.apache.org/faq.html).TheoriginalcreatorofbothAntandTomcatisJamesDuncanDavidson.
AnthasevolvedintothebuildtoolofchoiceforautomatingJavasoftwareprojects,whichmeansbuildingtheseprojectsfrombeginningtoend.ThisincludescompilingJavaclasses,creatingJARorWARfiles,andinitiatingfilesystem-relatedtaskssuchascreatingdirectoriesandmovingorcopyingfiles.AllofthesetasksarecontrolledbytheAntbuildfileforaspecificproject.
AnAntbuildfileisanXMLfilethatislaunchedfromthecommandlineandexecutesJavaclassesbehindthescenes.Antisalsoextensible;youcancustomizethistooltosuityourownpurposes.Inaddition,Antiscross-platformandveryportable,sinceitisbasedonXMLandJava.Oncewebdevelopersbecomefamiliarwiththishandyandpowerfultool,theyfindthatitgreatlyeasesthetaskofcompiling,packaging,andinevitablyalteringandredeployingtheirwebapplications.
ThischapterfirstdescribeshowtodownloadAntandsetituponyoursystem,andthenexplainsAnttargetsandtasksforthosewhoarenewtoAnt.TherestofyoucanmerrilymoveontootherrecipesdescribinghowtocreateaclasspaththatincludesthenecessaryTomcatJARfiles,createWARandJARfiles,anduseAnttoexecuteTomcat'sManagerapplication.
Recipe4.1ObtainingandSettingUpAnt
Problem
YouwanttodownloadandsetupApacheAntonyourcomputer.
Solution
Pointyourbrowsertohttp://ant.apache.org/,downloadthebinaryorsourcedistributionofAnt,thenfollowtheinstructionsgiveninthisrecipeandontheAntsupportsite.
Discussion
ThebinarydistributionofApacheAntcanbedownloadedfromhttp://ant.apache.org/bindownload.cgi.Youcanalsodownloadthesourcedistribution,whichcontainstheJavasourcefilesforAnt,fromhttp://ant.apache.org/srcdownload.cgi.YoumusthavetheJavaSoftwareDevelopmentKit(SDK)installed.
Antv1.5.3willbethelastreleasethatsupportsJDK1.1.Antv1.5.1canrunwithJDK1.1,althoughsometasksworkonlyonJDK1.2.
TouseAnt,youmusthaveaJavaAPIforXMLProcessing(JAXP)-compliantXMLparseravailableonyourclasspath.ThebinaryAntdistributionincludestheApacheXerces2XMLparser.IfyouoptforadifferentJAXP-compliantparser,youshouldremovexercesImpl.jarand
xmlParserAPIs.jarfromAnt'stop-level/libdirectory(asinjakarta-ant-1.5.1/lib)andputtheJARfile(s)forthealternativeparserintoAnt's/libdirectory.Youcanalsoaddthemdirectlytoyouruserclasspath.
TheuserclasspathistheclasspathrepresentedbytheCLASSPATHenvironmentvariableonyourmachine.Thisclasspathoverridesthedefaultvaluefortheuserclasspath(.,orthecurrentdirectory).Thejavacommand-linetool's-cpor-classpathswitchesoverridetheCLASSPATHenvironmentvariable.TheuserclasspathcanalsobesetbyaJARfilespecifiedbythejavatool's-jarswitch.Thisdesignationinturnoverridestheotherwaysofspecifyingaclasspath.Thebottomlineisthatitiseasiertoplaceyourparserofchoiceinthejakarta-ant-1.5.1/libdirectoryinsteadoffoolingaroundwiththeseclasspathissues.
ThecompleteinstallationdirectionsforAntandlinkstorelatedWebpagesareathttp://ant.apache.org/manual/index.html.
TakethefollowingstepstogetAntrunningonyourmachine:
1. Unpackthecompressedfile(inZIPorTARformat)containingtheAnttool.WithAntv1.5.1,unpackingthedistributionfilecreatesadirectorycalledjakarta-ant-1.5.1.
SettheANT_HOMEenvironmentvariabletothedirectorywhereyouinstalledAnt.OnUnix,thiscanbeaccomplishedbytypingacommand-linephrase:
exportANT_HOME=/usr/local/jakarta-ant-1.5.1
OnWindowstype:
setANT_HOME=h:\jakarta-ant-1.5.1
Addthe<Ant-installation-directory>/bindirectorytoyourPATHenvironmentvariable.Thisallowsthedevelopertochangetoanyworkingdirectorywithabuild.xmlfileandtypeanttorunthisfile(readthenextrecipeforadescriptionofexecutingabuild.xmlfile).The<Ant-
installation-directory>/bindirectorycontainsthescriptswhichlaunchtheJavaclassesthatformthebasisofAnt.
Optionally,settheJAVA_HOMEenvironmentvariabletothedirectorywhereyourJDKisinstalled.YoumightaswellsettheJAVA_HOMEenvironmentvariable,becausethescriptsthatareprovidedwithAntinits/bindirectorycanthenautomaticallyaddtherequiredJDK-relatedclasseswhenyouwanttousethejavacorrmictasks.TasksareXMLelementsthatdocertainjobsinAntfiles,suchaswar(tocreateWebArchivefiles)andjavac(tocompileJavaclasseswithAnt).
Testyourinstallationbytypingant-version.Ifeverythinggoeswell,thiscommandproducesareturnvaluelikethis:
K:\>ant-version
ApacheAntversion1.5.1compiledonOctober22002
SeeAlso
Recipe4.2onusingAnttargets;Recipe4.3onincludingTomcatJARfilesintheAntclasspath;Recipe4.4oncompilingaservletwithAnt;Recipe4.5oncreatingaWARfilewithAnt;Recipe4.6onusingAnttocreateJARfiles;Recipe4.7andRecipe4.8onstartingandstoppingTomcatwithAnt;Recipe2.1andRecipe2.6ondeployingwebapplicationsusingAnt;theApacheAntmanual:http://ant.apache.org/manual/index.html;theApacheAntProject:http://ant.apache.org.
Recipe4.2UsingAntTargets
Problem
YouwanttocreatetargetelementsfordevelopingwebapplicationswithanAntbuildfile.
Solution
Createoneormoretargetelementsaschildelementsofaprojectelement.Makesurethetargetshavetherequirednameattributeandvalue.
Discussion
AnAntbuildfileisanXMLfileinotherwords,aplaintextfilethatincludeselementsandattributes.Example4-1showsanAntfilethatechoesamessagetotheconsole.Asmentionedintheintroduction,AntfilesexecuteJavacodebehindthescenes.Thewayyoucontrolthedesiredactionsofyourbuildfileisbyarrangingoneormoretargetelementsinsidetheprojectrootelement.
Example4-1.AnAntbuildfilethatechoesaconsolemessage
<projectname="Cookbook"default="echo-message"basedir=".">
<targetname="echo-message"
description="Echoingamessagetotheconsole">
<echomessage="HellofromthefirstAntfile"/>
</target>
</project>
Antfileshaveoneprojectrootelement,whichmusthaveadefaultattributeandvalue.Thedefaultattributespecifiesthetargetthatrunsifnoothertargetsareidentifiedonthecommandline.Thenameandbasedirattributesareoptional.Thenameattribute,asyoumighthaveguessed,givestheprojectelementadescriptivename.Thebasedirattributespecifiesthedirectorybywhichpathsthatarereferredtointhefilearecalculated.Itsdefaultvalueisthedirectorycontainingthebuildfile.
Whataretargets?Theyaregroupsoftasks,representedinAntbyatargetelement.Targetsgrouponeormoretasks(whichareinturnrepresentedbyataskelement)intologicalandnamedunitsofcontrol,similartoJavamethods.
TasksincludeactionsthatcompileJavafiles(thejavactask),copyfilesfromonelocationtoanother(copy),andcreateJARorWARfiles(aptlynamedjarandwar).Forinstance,theecho-messagetargetinExample4-1callstheechotask.
Thetarget'snameinExample4-1isecho-message,whichisjustanamethatIcreatedforit.Atarget'sdescriptionattributeisoptional,asarethreeotherattributes:depends,if,andunless.I'llexplainthepurposeofdependsshortly;theifandunlessattributesallowtheconditionalexecutionoftargets.
AslongasAntisproperlysetuponyourcomputer,hereiswhatthecommand-linesequenceforexecutingthisexamplebuild.xmlfilemightlooklike:
H:\book\cookbook\sec1\sec1_3>ant
Buildfile:build.xml
echo-message:
[echo]HellofromthefirstAntfile.
BUILDSUCCESSFUL
Totaltime:3seconds
First,theXMLfilewiththeprojectrootelementissavedwiththefilenamebuild.xml.Thentheuserchangestothedirectorythatcontainsthisfileandtypesant,withoutanyoptions.Antthenlooksforafilecalledbuild.xmlinthecurrentdirectoryandrunstheproject'sdefaulttarget(inExample4-1,theecho-messagetarget).
Youcangivethebuildfileanameotherthanbuild.xml,butthenyouneedtorunAntwiththe-buildfileoption:
ant-buildfiledev.xml
MostbuildfilesinvolveseveraltargetsthatexecuteinacertainsequencetoinitiateJavadevelopmenttasks.Example4-2demonstratesthedependsattribute.Thisexampleshowshowtoexecuteseveraltargetsinaspecifiedsequence.
Example4-2.Usingthedependstargetattributetolaunchasequenceoftargets
<projectname="Cookbook"default="echo-message"basedir=".">
<targetname="init">
<propertyname="name"value="BrucePerry"/>
</target>
<targetname="show-props"depends="init">
<echomessage=
"The'name'propertyvalueis:${name}"/>
<echomessage=
"OSnameandversionis:${os.name}${os.version}"/>
<echomessage=
"YourJavahomeis:${java.home}"/>
</target>
<targetname="echo-message"depends="show-props">
<echomessage=
"HellofromthefirstAntfileindirectory:${basedir}"/>
</target>
</project>
Thistime,insteadofjustonetarget,theprojectelementhasseveralnestedtargets.Theecho-messagetargetisstillthedefaulttarget,butitsbehaviorhaschangedduetothevalueofitsdependsattribute.ThisoptionalattributespecifiesthenameofoneormoreAnttargetsthatmustbeexecutedpriortothecurrenttarget.Inotherwords,theecho-messagetargetspecifies,"Idependontheshow-propstarget,soexecuteitbeforeme."Theshow-propstarget,however,alsohasadependsattributethatindicatesarelianceontheinittarget.Asaresult,thisbuildfileestablishesasequenceforexecutingitstargets:init show-props echo-message.
Theresultofrunningthepriorbuildfileatthecommandlineisshownhere:
H:\book\cookbook\sec1\sec1_3>ant
Buildfile:build.xml
init:
show-props:
[echo]The'name'propertyvalueis:BrucePerry
[echo]OSnameandversionis:WindowsNT4.0
[echo]YourJavahomeis:h:\jdk1.3.1_02\jre
echo-message:
[echo]HellofromthefirstAntfileindirectory:
H:\book\cookbook\sec1\sec1_3
BUILDSUCCESSFUL
Totaltime:2seconds
Hereiswhatthisbuildfileaccomplishes:
1. Theinittargetfirstcreatesanamepropertythatcontainsthevalue"BrucePerry".Thetargetusesthepropertytasktoaccomplishthis.RecallthattasksdotherealworkinAnt;targetsaresimplygroupingelementsthatcalloneormoretasks.
Theshow-propstargetthenechoesthevaluesofthenameproperty(createdbytheinittarget)andthreebuilt-inproperties:os.name,os.version,andjava.home.
Theecho-messagetargetissuesitsmessagetotheconsoleandreturnsthevalueofthebasedirproperty.Allofthetargetsusetheechotasktodelivertheirmessages.
Notethatthenamepropertywouldnotbesetiftheinittargetwasneverexecuted.Iftheshow-propstargetisdefinedasseenhere,therewillbeproblems:
<targetname="show-props">
...</target>
However,itisproperlydefinedasfollows:
<targetname="show-props"depends="init">
...</target>
Withoutthedependsattribute,theinittargetwouldneverbeexecuted,becausethebuildfile'sexecutionsequencewouldlooklikeshow-props echo-message.Thenamepropertywouldneverbegivenavalue.
Antbuildfilesareusuallymuchmorecomplexthantheseexamples,whichismoreofatestamenttoAnt'spowerthanevidenceofpoordesign.Chapter2showshowtodeployindividualservletsandwebapplicationswithmoreextensiveAntfiles.
SeeAlso
Recipe4.1ondownloadingandsettingupAnt;Recipe4.3onincludingTomcatJARfilesintheAntclasspath;Recipe4.4oncompilingaservletwithAnt;Recipe4.5oncreatingaJARfilewithAnt;Recipe4.7andRecipe4.8onstartingandstoppingTomcatwithAnt;Recipe2.1andRecipe2.6ondeployingwebapplicationsusingAnt;theAntmanualsectiononthepropertytask:http://ant.apache.org/manual/CoreTasks/property.html;theAntmanualsegmentontargets:http://ant.apache.org/manual/using.html#targets;theApacheAntmanualindexpage:http://ant.apache.org/manual/index.html;theApacheAntProject:http://ant.apache.org.
Recipe4.3IncludingTomcatJARfilesintheBuildFileClasspath
Problem
YouwanttoestablishanAntclasspaththatincludesvariousTomcatJARfiles.
Solution
Useapath-likestructuretodefinetheclasspath,thenrefertothisclasspathwheneveryouneedit.SpecifythedirectorieswherethenecessaryJARfilesarelocatedwithanexternalpropertiesfile.
Discussion
BeforeyoucancompileaservletusingAnt,youmustensurethattheservletAPIclassesareavailableontheclasspaththattheAntbuildfileisusingforcompilation.Forexample,the<Tomcat-installation-directory>/common/libdirectorycontainsservlet.jar,whichincludesthenecessaryclassesforcompilingaservlet.Inaddition,youmightwanttoincludethemail.jarcomponentfromthesamedirectorytocompileaservletthatusestheJavaMailAPI.Adifferentdirectory<Tomcat-installation-directory>/common/endorsedincludesthexmlParserAPIs.jarfile,whichyoumightspecifyontheclasspathtousetheassociatedSAXandDOMXMLprogrammingclasses.
Example4-3definesaclasspathusingapathXMLelement.Acompile-servlettargetfurtherdownintheXMLfilethenusesthedefinedclasspathtocompileaservlet.
Example4-3.DefiningaclasspathincludingTomcatJARfiles
<projectname="Cookbook"default="compile-servlet"basedir=".">
<!--includecompiled-servletandtomcat-dirproperties-->
<propertyfile="global.properties"/>
<pathid="servlet-classpath">
<filesetdir="${tomcat.dir}/common/lib">
<includename="*.jar"/>
</fileset>
<filesetdir="${tomcat.dir}/common/endorsed">
<includename="*.jar"/>
</fileset>
</path>
<targetname="compile-servlet">
<echomessage="Compilingtheservlet...."/>
<javacsrcdir="${src}"destdir="${build}">
<includename="${compiled.servlet}.java"/>
<classpathrefid="servlet-classpath"/>
</javac>
</target>
</project>
Usingthepathelement,theclasspathcanbedefinedsimilarlytoaninstancevariableofaJavaclass,anditsvaluecanthenbeusedthroughoutthebuildfile.Theadvantageofthisapproachisthattheclasspathmaybeverycomplex,butithastobedefinedonlyonce.WheneverthereisaneedforaclasspathinanAntfile,theclasspathelementanditsrefidattributecanbeusedtopullinthedefinedclasspath.InExample4-3,thepathelementisgivenauniqueID,"servlet-classpath."Thedevelopercreatesthisnametouniquelyidentifythepath-likestructure.
AnothercoretypeofAnttaskisafileset.filesetsareelementsthatrepresentgroupsoffiles.ThetwonestedfilesetsintheexamplehavedirattributesthatspecifytwodirectoriesundertheTomcatinstallationdirectory:./common/liband./common/endorsed.ThesearedirectoriesthatcontainmanyimportantJavalibraries,suchasservlet.jarandmail.jar.Afilesetelement'snestedincludeelementcreatesapattern(withthenameattribute)thatspecifiesthetypesoffilestoincludeineachfileset.Theexampleincludesallfilesinthespecifieddirectoriesendingin".jar".
IfyouwantedtofurtherrefinethetypesofJARfilesthatareincludedinafileset,youcouldusethefileset'snestedexcludeelement:
<filesetdir="${tomcat.dir}/common/lib">
<includename="*.jar"/>
<excludename="commons*.jar"/>
</fileset>
Thepattern"commons*.jar"excludesalltheJARfilesfromtheclasspaththatbeginwiththeword"commons,"followedbyzeroormorecharactersanda".jar"suffix.
Thecompile.servlettargetinExample4-3echoesamessagetotheconsole,thenusesthejavactasktocompileaservlet.
ThiscodefromExample4-3makestwopropertiesthataredefinedinanotherfileavailabletotheAntbuildfile:
<propertyfile="global.properties"/>
Hereiswhattheglobal.propertiesfilelookslike:
tomcat.dir=k:/jakarta-tomcat-4.1.12
compiled.servlet=MyTask
src=.\src
build=.\build
Thepropertycompiled.servletevaluatestothenameoftheJava
sourcefilethatisbeingcompiled.Thetomcat.dirfileisthefilepathtotheTomcatrootdirectory.
InExample4-3,theclasspathelementisnestedinsidethejavactask,asin:
<javacsrcdir="${src}"destdir="${build}">
<includename="${compiled.servlet}.java"/>
<classpathrefid="servlet-classpath"/>
</javac>
Theclasspathelement'srefidattributepullsintheclasspaththatwasdefinedearlierinthebuildfile(includingalltheTomcatJARsin./common/liband./common/endorsed).Thevalueoftherefidattributeistheidofthepathelement("servlet-classpath").Inotherwords,thepathelementinExample4-3representsaclasspath;theelement'sidornameis"servlet-classpath."
IfitisnecessarytoaddmoreclassesorJARstotheclasspaththatyouaredefininginanAntfile,thenaddanothernestedfilesettothepathelement.Example4-4addsallofthecontentsofthebuilddirectorytotheclasspathdefinedbyExample4-3(alongwiththeTomcat-relatedJARs)byaddingathirdnestedfileset.
Example4-4.Nestingthreefilesetsinapathstructure
<pathid="servlet-classpath">
<filesetdir="${tomcat.dir}/common/lib">
<includename="*.jar"/>
</fileset>
<filesetdir="${tomcat.dir}/common/endorsed">
<includename="*.jar"/>
</fileset>
<filesetdir="./build"/>
</path>
Anidiomthatoftenappearsinpath-relatedpatternsis**,whichmeanszeroormoredirectories.Forexample,thefollowingfilesettagincludesallofthefilescontainedinanynestedimagesfolders(srcisapropertynamepointingtothesourcedirectoryofthisfileset),nomatterhowdeeplytheyarenested:
<filesetdir="${src}">
<includename="**/images/*"/>
</fileset>
SeeAlso
Recipe4.1ondownloadingandsettingupAnt;Recipe4.2onwritingAnttargets;Recipe4.4oncompilingaservletwithAnt;Recipe4.5oncreatingaWARfilewithAnt;Recipe4.6onusingAnttocreateJARfiles;Recipe4.7andRecipe4.8onstartingandstoppingTomcatwithAnt;Recipe2.1andRecipe2.6ondeployingwebapplicationsusingAnt;theAntmanualsectiononthepropertytask:http://ant.apache.org/manual/CoreTasks/property.html;theAntmanualsegmentontargets:http://ant.apache.org/manual/using.html#targets;theApacheAntmanualindexpage:http://ant.apache.org/manual/index.html;theApacheAntProject:http://ant.apache.org.
Recipe4.4CompilingaServletwithanAntBuildFile
Problem
Youwanttosetupasimplebuildfilethatyoucanusetocompileindividualservlets,withouthardcodingservletnames.
Solution
DesignabuildfilesothatthenameoftheJavaclasstocompilecanbesetfromanexternalpropertiesfileorfromthecommandline.
Discussion
IfyouarenotusinganIDEtodevelopandcompileyourservlets,anAntbuildfilecanautomatethecompilingofyoursourcefiles.Inordertomakethisbuildfilereusable,youshoulddesignittogetthenameofthefilefromanexternalpropertiesfileorfromthecommandline.
Ant'sadvantagescometotheforewhenitisusedtoautomatealloftheaspectsofbuilding,archiving,anddeployingawebapplication.However,youcanalsouseAntasakindofbatchprocessor.Inthisrecipe,IuseAnttodynamicallychooseaJavafiletocompile.
Thebuild.xmlfileinExample4-5importsacoupleofpropertiesfromabuild.propertiesfile,includingthenameoftheservlettobecompiled.OnewaytochooseadifferentJavafiletocompileistochangethevalueofthecompiled.servletpropertyinthisfile,withouttouchingthebuildfile:
tomcat.dir=/users/bruceper/java/jakarta-tomcat-4.1.12
compiled.servlet=MyServlet
TorunExample4-5,changetothedirectorywherethebuild.xmlfileislocatedandtypeantwithoutanyoptions.
IfyouarerunninganAntbuildfilewithadifferentname,thenlaunchitwiththiscommandline:
ant-buildfileant_compiler.xml
First,thisfileimportsthetomcat.dirandcompiled.servletpropertiesfromabuild.propertiesfile.Thisfileislocatedinthesamedirectoryasthebuildfile.Thetomcat.dirpropertyisusedtocreateaclasspathcomposedoftheJARfilesintwodirectoriesthatareapartofTomcat'sdirectorytree(seeRecipe4.2).
Example4-5.CompilingaservletwithanAntbuildfile
<projectname="servletcompiler"default="compile"basedir=".">
<propertyfile="build.properties"/>
<pathid="servlet-classpath">
<filesetdir="${tomcat.dir}/common/lib">
<includename="*.jar"/>
</fileset>
<filesetdir="${tomcat.dir}/common/endorsed">
<includename="*.jar"/>
</fileset>
</path>
<targetname="init"
description="Initializessomeproperties.">
<echomessage="Initializingproperties."/>
<propertyname="build"value="./build"/>
<propertyname="src"value="./src"/>
</target>
<targetname="prepare"depends="init">
<echomessage="Cleaningupthebuilddirectory."/>
<deletedir="${build}"/>
<mkdirdir="${build}"/>
</target>
<targetname="compile"depends="prepare"
description="Compiletheservlet">
<echomessage="CompilingtheJavafile"/>
<echomessage="${compiled.servlet}.java..."/>
<javacsrcdir="${src}"destdir="${build}">
<includename="${compiled.servlet}.java"/>
<classpathrefid="servlet-classpath"/>
</javac>
</target>
</project>
Theinittargetcreatestwopropertiesrepresentingthesource(src)anddestination(build)directoriesofthetargetservlet.TheJavafilewaitingtobecompiledislocatedinansrcdirectory.Atypicalbuildfilealsohasaninittargetthatinitializesseveralmoreproperties.Sincethecompiletargethasadependsattributethatspecifiesthepreparetarget,andthepreparetargetdependsoninit,thenthebuildsequencelookslikeinit prepare compile.
Thepreparetargetjustcleansupthebuilddirectorytoensurethatthebuilddirectorycontainsthelatestcompiledclasses.
ThecompiletargetusesthejavactasktoactuallycompiletheJava
file.javachasattributesthatspecifythesourceanddestinationdirectoriesoftheJavafile(s)thatitwillattempttocompile.Example4-5usesthesrcandbuildpropertiestoprovidevaluesfortheseattributes.Twonestedelementsofthejavactaskcompilethespecifiedservletfileandprovidetheclasspaththatthejavactaskuses(seeRecipe4.2).
Hereistheconsoleoutputafterrunningthisbuildfile(withsomeeditingforreadability):
init:
[echo]Initializingproperties.
prepare:
[echo]Cleaningupthebuilddirectory.
[delete]Deletingdirectory
/Users/bruceper/books/cookbook/sec1/sec1_3/build
[mkdir]Createddir:
/Users/bruceper/books/cookbook/sec1/sec1_3/build
compile:
[echo]CompilingtheJavafileMyServlet.java...
[javac]Compiling1sourcefileto
/Users/bruceper/books/cookbook/sec1/sec1_3/build
BUILDSUCCESSFUL
Totaltime:6seconds
Usingthecommandlinetodeclarethetargetservlet
Whatifyouwanttochangetheservletthatyouarecompiling,butarenotinclinedtotypethenewJavafilenameintothebuild.propertiesfile?Runningthebuild.xmlAntfilefromthecommandlineinthefollowingmannerwilloverridetheimportedcompiled.servletproperty:
ant-Dcompiled.servlet=AnotherServlet
AnotherServlet.javaisthefilenameinthisexampleoftheJavafilethatawaitscompilationinthesrcdirectory.Thisfragmentofoutputshowsthatanypropertiespassedinfromthecommandlineoverridepropertiesofthesamenamecreatedwithinorimportedintothebuildfile:
compile:
[echo]CompilingtheJavafileAnotherServlet.java...
[javac]Compiling1sourcefileto
/Users/bruceper/books/cookbook/sec1/sec1_3/build
Thejavactaskcompilesonlyonlythejavafilesinthesrcdirectorythatdonothaveacorrespondingclassfile,orincaseswheretheclassfileisolderthanitscorresponding.javafile.Asalways,checktheAntmanualtofindoutaboutallthedifferentvariationsandattributesofjavac:http://ant.apache.org/manual/CoreTasks/javac.html.
Ifyouwanttocopythecompiledservletclasstoawebapplicationdirectory,youcouldaddadeploy-servlettargetthatusesthecopyAnttask:
<targetname="deploy-servlet"depends="compile">
<echomessage=
"CopyingtheservlettoTomcatwebapp"/>
<copytodir="${tomcat.webapps}/WEB-INF/classes">
<filesetdir="${build}"/>
</copy>
</target>
Thecopytasktakesitsnestedfileset,whichrepresentsthecontentsofthedirectorynamedbythebuildpropertyvalue,andcopiestheseclassfilestotheWEB-INF/classesdirectoryofTomcat'sdefaultwebapplication.
SeeAlso
Recipe4.1ondownloadingandsettingupAnt;Recipe4.2onwritingAnttargets;Recipe4.3oncreatingaclasspathforanAntfile;Recipe4.5oncreatingaWARfilewithAnt;Recipe4.6onusingAnttocreateJARfiles;Recipe4.7andRecipe4.8onstartingandstoppingTomcatwithAnt;Recipe2.1andRecipe2.6ondeployingwebapplicationsusingAnt;the
Antmanualsectiononthepropertytask:http://ant.apache.org/manual/CoreTasks/property.html;theAntmanualsegmentontargets:http://ant.apache.org/manual/using.html#targets;theApacheAntmanualindexpage:http://ant.apache.org/manual/index.html;theApacheAntProject,http://ant.apache.org.
Recipe4.5CreatingaWARFilewithAnt
Problem
YouwanttouseAnttocreateaWebARchive(WAR)file.
Solution
UsetheAntwartask.
Discussion
AWARfileisawebapplicationarchivethatcontainsservletclasses,JSPfiles,HTMLfiles,imagedirectories,JARfiles,XMLconfigurationfiles,andotherresourcesthatawebapplicationdependson.TheWARisdeployedonawebcontainerlikeTomcatinordertomakethewebapplicationavailabletothecontainer'susers.AntincludesawartaskthatmakesiteasytogenerateaWARfromadirectorystructurethatcontainsthenecessarywebapplicationfiles.
Example4-6isastandalonebuildfilethatcreatesaWARfile.ItcouldeasilycompriseonetargetinacomplexbuildfilethatcompilesJavafiles,createstheWAR,anddeploystheapplication(seeRecipe2.6).
Thisexamplecreatesabuildsequenceofinit preparecreate-war.Theinittargetcreatesseveralpropertiesthatrefertodirectories,suchasthebuilddirectorycontainingtheservletclassfiles.Thecontext-pathpropertyprovidesthecontextpathforthewebapplication,andinthiscase,thenameoftheWARfile(myapp.war).
Youexecutethisbuildfilefromacommandpromptwhoseworking
directoryisthewebapplication'srootortop-leveldirectory.
Example4-6.AnAntfileusingthewartask
<projectname="war-task"default="create-war"basedir=".">
<targetname="init"
description="Initializessomeproperties.">
<echomessage="Initializingproperties."/>
<propertyname="build"value=".\build"/>
<propertyname="src"value=".\src"/>
<propertyname="dist"value=".\dist"/>
<propertyname="lib"value=".\lib"/>
<propertyname="web"value=".\web"/>
<propertyname="meta"value=".\meta"/>
<propertyname="context-path"value="myapp"/>
</target>
<targetname="prepare"depends="init">
<echomessage=
"Cleaningupthebuildanddistdirectories."/>
<deletedir="${build}"/>
<mkdirdir="${build}"/>
<deletedir="${dist}"/>
<mkdirdir="${dist}"/>
</target>
<targetname="create-war"description=
"createsawebapplicationarchivefile"
depends="prepare">
<wardestfile="${dist}/${context-path}.war"
webxml="${meta}/web.xml">
<classesdir="${build}"/>
<libdir="${lib}"/>
<filesetdir="${web}"/>
</war>
</target>
</project>
Ifthebuildfilewascalledwar-task.xml,thentheAntfileisexecutedwiththiscommandline:
ant-buildfilewar-task.xml
Thecreate-wartargetcallsthewartask.
Thewartask'sdestfileattributeisrequired;itspecifiesthelocationoftheresultingWARfile.Example4-6createstheWARinthedistdirectory.Thewebxmlattributespecifiesthelocationofthewebapplication'sdeploymentdescriptor.Thiswebapplication'sweb.xmlfile(inthisexample)islocatedinthemetadirectory.
Theexamplewartaskhasthreenestedelements:classes,lib,andfileset.ThedirattributeoftheclasseselementpointstothedirectorythatcontainstheJavaclassesthatarelocatedintheWEB-INF/classesdirectory.ThewartaskautomaticallycreatestheWEB-INF/classesdirectoryintheWARfile.Thistaskalsoreproducesallthepackage-relateddirectoriesinthebuilddirectorywhenitcreatesWEB-INF/classes.Inotherwords,ifthebuilddirectoryincludesacom/jspservletcookbookdirectorystructure,thentheWARwillhavethesamestructureinWEB-INF/classes.
ThelibelementgrabsandstoresanyJARfilesthatwillbelocatedintheWARfile'sWEB-INF/libdirectory.Finally,thefilesetnested
element,inthiscase,pullsinallthestaticfilesandanynestedimagedirectoriesthatarecontainedin/webandplacesthematthetopleveloftheWAR'sdirectorytree.Hereiswhattheoutputofthisbuildfilelookslike(withsomeeditingforreadability):
init:
[echo]Initializingproperties.
prepare:
[echo]Cleaningupthebuildanddistdirectories.
[delete]Deletingdirectory
/Users/bruceper/books/cookbook/build
[mkdir]Createddir:
/Users/bruceper/books/cookbook/build
[delete]Deletingdirectory
/Users/bruceper/books/cookbook/dist
[mkdir]Createddir:
/Users/bruceper/books/cookbook/dist
create-war:
[war]Buildingwar:
/Users/bruceper/books/cookbook/dist/myapp.war
ThewartaskhasnumerousotheroptionalattributesthatareexplainedintheAntmanualathttp://ant.apache.org/manual/CoreTasks/war.html.
SeeAlso
Recipe4.1ondownloadingandsettingupAnt;Recipe4.2onwritingAnttargets;Recipe4.3oncreatingaclasspathforanAntfile;Recipe4.4oncompilingaservletwithAnt;Recipe4.6onusingAnttocreateJARfiles;Recipe4.7andRecipe4.8onstartingandstoppingTomcatwithAnt;Recipe2.1andRecipe2.6ondeployingwebapplicationsusingAnt;theAntmanualsectiononthepropertytask:http://ant.apache.org/manual/CoreTasks/property.html;theAntmanualsegmentontargets:http://ant.apache.org/manual/using.html#targets;
theApacheAntmanualindexpage:http://ant.apache.org/manual/index.html;theApacheAntProject:http://ant.apache.org.
Recipe4.6CreatingaJARFilewithAnt
Problem
YouwanttocreateaJARfilewithAnt.
Solution
Usethebuilt-injartask.
Discussion
ThejartaskautomatesthecreationofJARfiles.LikethewartaskforWARs,thejartaskallowsyoutoautomatethecommand-linephrasesyouwouldhavetotypeinforcreatingJARs.Inthisway,buildfilesusingthejartaskaresomewhatlikeshellscriptsorbatchfilesforcreatingJARs.TheSunMicrosystemsJARfilespecificationcanbefoundathttp://java.sun.com/j2se/1.4/docs/guide/jar/jar.html.
Inwebapplications,JARfilesareusedtocontainseparatecodelibrariesthatthewebapplicationdependson,suchasadatabasedriver.Theyarelocatedinawebapplication'sWEB-INF/libdirectory.Example4-7showsanAnttargetthatusesthejartasktocreateaJAR,andthencopiestheJARfiletothelibdirectoryofawebapplication.TheseactionsprecedethearchivingofthewebapplicationintoaWARfile,whichcanbeincludedinthesamebuildfiletoautomateeverythingatonce(seeRecipe4.5oncreatingWARfiles).
Example4-7.CreatingaJARfilewithAnt
<projectname="jar-task"default="create-jar"basedir=".">
<targetname="init"
description="Initializessomeproperties.">
<echomessage="Initializingproperties."/>
<propertyname="dist"value="dist"/>
<propertyname="web"value="web"/>
<propertyname="meta"value="meta"/>
<propertyname="jar-name"value="myutils"/>
</target>
<targetname="prepare"depends="init">
<echomessage=
"Cleaningupthebuildanddistdirectories."/>
<deletedir="${dist}"/>
<mkdirdir="${dist}"/>
</target>
<targetname="create-jar"
description="createsaJARarchivefile"
depends="prepare">
<jardestfile="${dist}/${jar-name}.jar"
basedir="../../"
includes="**/*.class**/${web}/*.html">
<filesetdir="../../images"/>
</jar>
</target>
</project>
Thisbuildfilecontainsthreetargetsinthebuildsequenceinitprepare create-jar.ThesetargetscreatesomepropertiesandcleanupadirectorycalleddistthatcontainstheresultantJARfile.Thecreate-jartargetcallsthejartask,whichlookslike:
<jardestfile="${dist}/${jar-name}.jar"basedir="../../"
includes="**/*.class**/${web}/*.html">
<filesetdir="../../images"/>
</jar>
ThedestfileattributeofthejarelementspecifiesthelocationandnameoftheJARfileafteritiscreated.Iusedapropertycalledjar-namehere,sothattheusercanrunthisAntfilefromthecommandlineandfeedanewJARfilenameintothebuildfileifneedbe,asin:
ant-Djar-name=mynewjar.jar
Rememberthatanypropertiesspecifiedwiththe-Dswitchoverridethepropertiesofthesamenamedefinedinsidethebuildfile.
Thebasedirattributeofthejartaskidentifiesthetop-leveldirectoryoffilesthatwillbeincludedintheJAR.Intheexample,thepattern../../means"gouptwodirectoriesfromthebasedirofthisproject";inotherwords,gouptwodirectoriesfromwheretheAntbuildfileislocated.
Theincludesattributehastwospace-separatedpatterns(youcanalsoseparatethemwithacomma).ThepatternsfurtherrefinethetypesoffilesthatwillbeincludedintheJARfile.Thefirstpatternspecifiesthe
inclusionofallthefilesendingwiththe.classsuffixthatarelocatedinzeroormoredirectoriesbeneaththebasedirlocation.ThisJAR,asaresult,containsalloftheJavaclassfilesinalldirectoriesnestedbeneaththebasedirectory;theJARreproducesanynesteddirectoriesthatitfindswiththeclassfiles.Theotherpattern(**/${web}/*.html)takesalldirectoriesnestedbeneaththebasedirectorycalledwebandincludesanyfilesthatendwith.htmlintheJAR.Onceagain,thenesteddirectorieswillbeincludedwiththeJARandtheHTMLfiles.
Finally,afilesetelementnestedwithinthejartaskgrabsallthecontentsofthe../../imagesfolderandincludesthemintheJAR,butitdoesnotincludetheimagesfolderitself.AwaytoincludetheimagesfolderanditscontentsatthetopleveloftheJARistochangethejartaskto:
<jardestfile="${dist}/${jar-name}.jar"basedir="../../"
includes="**/*.class**/${web}/*.html**/images/*.gif
Thistaskaddsathirdpatterntotheincludesattribute(**/images/*.gif),whichgrabsalltheGIFfilescontainedbyanyimagesdirectoriesthatarenestedinthebasedirectory(thevalueofthejarelement'sbasedirattribute).AnimagesdirectorywillbeincludedintheJARifoneisfound.
The**patternisoftenusedinAntelements;itmeans"zeroormoredirectories."
Manifest
ThejartaskcreatesaMETA-INF/MANIFEST.MFfilefortheJARifthejartask'smanifestattributedoesnotappear.Thedefaultmanifestlookslikethis:
Manifest-Version:1.0
Created-By:ApacheAnt1.5.1
IfyouwanttospecifythelocationofyourownmanifestfileforreasonssuchassigningaJARfileorspecifyingthefilethatcontainsthemain()methodinanexecutableJAR,usethejartask'smanifestattribute.ThisoptionalattributecanbeeitherthefilelocationofthemanifestorthenameofanotherJARthathasbeenaddedbyusinganestedfilesetelement.IfitisaJAR,thetasklooksinthatJARfortheMETA-INF/MANIFEST.MFmanifest.
SeeAlso
Recipe4.1ondownloadingandsettingupAnt;Recipe4.2onwritingAnttargets;Recipe4.3oncreatingaclasspathforanAntfile;Recipe4.4oncompilingaservletwithAnt;Recipe4.7andRecipe4.8onstartingandstoppingTomcatwithAnt;Recipe2.1andRecipe2.6ondeployingwebapplicationsusingAnt;theAntmanualsectiononthepropertytask:http://ant.apache.org/manual/CoreTasks/property.html;theAntmanualsegmentontargets:http://ant.apache.org/manual/using.html#targets;theApacheAntmanualindexpage:http://ant.apache.org/manual/index.html;theApacheAntProject:http://ant.apache.org.
Recipe4.7StartingaTomcatApplicationwithAnt
Problem
YouwanttostartawebapplicationonTomcatusinganAntfile.
Solution
UsetheTomcat-suppliedStartTasktasksothatAntcanmanageTomcat.
Discussion
TheTomcatservletandJSPcontainerincludesabuilt-inwebapplicationcalled"Manager"thatyoucanusetostart,stop,deploy,andinitiateotheradministrativetaskswithwebapplications.Tomcatmakesthisapplicationavailablefromthe/managercontextpath.
TomcatVersion4(andlater)includesJavaclassesthatallowdeveloperstousetheManagerapplicationfromtheirAntbuildfiles.TheadvantageofusingtheManagerapplicationfromAntisthatyoudonothavetoconfiguretheconf/server.xmlfiletomakethewebapplicationdynamicallyreloadable(seeRecipe2.2).Inaddition,youcanstartorstopasinglewebapplicationwithoutdisruptingotherTomcatapplications.
TheManagerdocumentationisfoundonlineathttp://jakarta.apache.org/tomcat/tomcat-4.1-doc/printer/manager-howto.html
TakethesestepstostartTomcatfromAnt:
1. MakesureyouhavethenecessaryJARfilerequiredtousetheAnttaskforstartingTomcat:<Ant-installation-directory>/lib/catalina-ant.jar.CopythisJARfromthe<Tomcat-installation-directory>/server/libdirectorytoyour<Ant-installation-directory>/libdirectory(otherwiseknownasANT_HOME/lib).
MakesuretheTomcatuserdatabaseincludesausernamethatislinkedtothemanagerrole.OnlyadministrativeusersshouldbeauthorizedtostartandstopwebapplicationsusingtheManagertool.Theconf/tomcat-users.xmlfilemapsusersandpasswordstoroles.AuserhastobemappedtothemanagerroletobeabletousetheManagertool.Hereisanexampleofoneoftheseusermappingsintomcat-users.xml:
<userusername="doug"password="_1968dgw"roles="manager,dbadmin"/>
UsethetaskdefelementintheAntfiletodefinethecustomtaskandgiveitaname.Example4-8givesthetaskthenamestart,whichisusedbythetargetthatisresponsibleforstartingTomcat.
RuntheAntfileatthecommandlinebychangingtoitsdirectoryandtypingant.
Example4-8showsthetaskdefelementthatdefinesthestarttask,followedbythetargetthatstartsthespecifiedTomcatapplication.
Example4-8.StartingTomcatusinganAntfile
<projectname="MyProject"default="start-tomcat"basedir=".">
<taskdefname="start"classname="org.apache.catalina.ant.StartTask"/>
<!--importpropertiesspecifyingusername,password,url,andcontext-path-->
<propertyfile="global.properties"/>
<targetname="start-tomcat"
description="StartstheWebapplication">
<echomessage="Startingthedefaultapplication${context-path}..."/>
<start
url="${url}"
username="${username}"
password="${password}"
path="/${context-path}"/>
</target>
</project>
ThestarttaskhasfourattributesthatExample4-8setsusingaglobal.propertiesfile.Thisisatextfilecontainingfourname/valuepairs,whichareimportedintotheAntfileusingthepropertytask:
<propertyfile="global.properties"/>
Theglobal.propertiesfileislocatedinthesamedirectoryastheAntbuildfile.Herearethecontentsoftheglobal.propertiesfile:
url=http://localhost:8080/manager
username=bruce
password=bruce1957
context-path=home
TheurlpropertyspecifiestheTomcatManagerURL,theusernameandpasswordidentifytheuserwhoismappedintheTomcatuserdatabasetothemanagerrole,thecontext-pathpropertyspecifiesthecontextpathofthewebapplicationyouarestarting,andtheAntfileitselfspecifiestheopeningslash(/)characterforthecontextpath.
AnotherwaytopasspropertiestoanAntfileisonthecommandline:
ant-Dusername=bruce-Dpassword=bruce1957
-Durl=http://localhost:8080/manager
-Dcontext-path=home
Propertiesaddedonthecommandlineoverridethosespecifiedbythepropertytask.
LaunchthisAntfilebychangingtoitsdirectoryatthecommandlineandtypingantorant-buildfilebuildfile-name.Hereisthecommand-lineoutput:
H:\book\cookbook\code\chap4>ant-buildfilestart.xml
Buildfile:start.xml
start-tomcat:
[echo]Startingthedefaultapplicationhome...
[start]OK-Startedapplicationatcontextpath/home
BUILDSUCCESSFUL
Totaltime:4seconds
Ifanapplicationisstopped,itisunavailabletowebusers(seeRecipe4.8).Whentheapplicationisstartedagain,itcanreceiverequestsnormally.
TheTomcatmanagerapplicationcaninitiatemanyothercommonadministrativetaskssuchasdeployingapplications(seeRecipe2.6).
SeeAlso
TheTomcatManagerapplicationdescription:http://jakarta.apache.org/tomcat/tomcat-4.1-doc/manager-howto.html;Recipe4.1ondownloadingandsettingupAnt;Recipe4.2onwritingAnttargets;Recipe4.3oncreatingaclasspathforanAntfile;Recipe4.4oncompilingaservletwithAnt;Recipe4.5andRecipe4.6oncreatingWARandJARfiles;Recipe4.8onstoppingTomcatwithAnt;Recipe2.1andRecipe2.6ondeployingwebapplicationsusingAnt;theAntmanualsectiononthepropertytask:http://ant.apache.org/manual/CoreTasks/property.html;theAntmanualsegmentontargets:http://ant.apache.org/manual/using.html#targets;theApacheAntmanualindexpage:http://ant.apache.org/manual/index.html;theApacheAntProject:http://ant.apache.org.
Recipe4.8StoppingaTomcatApplicationwithAnt
Problem
YouwanttouseAnttostopaspecificTomcatwebapplication.
Solution
DefineataskintheAntfileusingataskdefelementandtheJavaclassorg.apache.catalina.ant.StopTask.
Discussion
Duringdevelopment,youmightneedtostopaTomcatwebapplicationsothatyoucanaddnewservletsordeployment-descriptorentries,andthenrestarttheapplication,allowingthechangestotakeeffect.Intheabsenceofaconf/server.xmlconfigurationtomaketheapplicationdynamicallyreloadable(seeRecipe2.2),youcanuseanAnttargettostopaparticularwebapplicationwithoutdisruptingtheotherrunningwebapplications.Thisistheoppositeofstartinganapplication(Recipe4.7);theapplicationistakenoutofserviceuntilyoustartitagain.
Theorg.apache.catalina.ant.StopTaskclassprovidesaconnectionbetweenAntandtheTomcatManagerapplication.Managerisabuilt-inwebapplication(atcontextpath/manager)thatyoucanusetoadministerotherTomcatwebapplications.
ImplementthesamefourstepsdiscussedinRecipe4.7tousethisstoptask:
1. MakesureyouhavethenecessaryJARfilerequiredtousetheAnttaskforstoppingTomcat:<Ant-installation-directory>/lib/catalina-ant.jar.CopythisJARfromthe<Tomcat-installation-directory>/server/libdirectorytoyour<Ant-installation-directory>/libdirectory(otherwiseknownasANT_HOME/lib).
MakesuretheTomcatuserdatabaseincludesausernamethatislinkedtothemanagerrole(seestep2ofRecipe4.7ifyouneedmoredetails).
Example4-9usesataskdefelementtogivethetaskthenamestop,whichisusedbythetargetthatisresponsibleforstoppingTomcat.
RuntheAntfileatthecommandlinebychangingtoitsdirectoryandtypingantorant-buildfilebuildfile-name.
Example4-9.UsingAnttostopawebapplication
<projectname="MyProject"default="stop-tomcat"basedir=".">
<taskdefname="stop"classname="org.apache.catalina.ant.StopTask"/>
<!--importpropertiesspecifyingusername,password,url,andcontext-path-->
<propertyfile="global.properties"/>
<targetname="stop-tomcat"
description="StopstheWebapplication">
<echomessage="Stoppingtheapplication${context-path}..."/>
<stop
url="${url}"
username="${username}"
password="${password}"
path="/${context-path}"/>
</target>
</project>
Thetaskdefdefinesataskforthisbuildfilecalledstop.Thedefinedtaskisthenusedinthebuildfile:
<stopurl="${url}"username="${username}"password="${password}"
path="/${context-path}"/>
Example4-9getsitspropertyvaluesfromapropertytaskthatimportsglobal.properties(thepropertyfileislocatedinthesamedirectoryastheAntbuildfile).Thepropertiesrepresent:
Theusernameandpasswordofauserwhoismappedtothemanagerroleinconf/tomcat-users.xml
TheURLtotheManagerapplication,asinhttp://localhost:8080/manager
Thecontextpathforthewebapplicationthatyouarestopping
TheTomcatmanagerapplicationcaninitiatemanyothercommonadministrativetaskssuchasdeployingapplications(seeRecipe2.6).
SeeAlso
TheTomcatManagerapplicationdescription:http://jakarta.apache.org/tomcat/tomcat-4.1-doc/manager-howto.html;
Recipe4.1ondownloadingandsettingupAnt;Recipe4.2onwritingAnttargets;Recipe4.3oncreatingaclasspathforanAntfile;Recipe4.4oncompilingaservletwithAnt;Recipe4.5andRecipe4.6oncreatingWARandJARfiles;Recipe4.7onstartingTomcatwithAnt;Recipe2.1andRecipe2.6ondeployingwebapplicationsusingAnt;theAntmanualsectiononthepropertytask:http://ant.apache.org/manual/CoreTasks/property.html;theAntmanualsegmentontargets:http://ant.apache.org/manual/using.html#targets;theApacheAntmanualindexpage:http://ant.apache.org/manual/index.html;theApacheAntProject:http://ant.apache.org.
Chapter5.AlteringtheFormatofJSPs
Introduction
Recipe5.1.PrecompilingaJSPinTomcat
Recipe5.2.PrecompilingaJSPinWebLogic
Recipe5.3.PrecompilingJSPswiththePrecompilationProtocol
Recipe5.4.MappingaJSPtoItsPageImplementationClass
Recipe5.5.CreatingaJSPfromScratchasaJSPDocument
Recipe5.6.GeneratinganXMLViewfromaJSP
Introduction
ThischaptercoverstwomeansofworkingwithJSPsthatfallslightlyoutsidethenorm.ThefirstmethodprecompilesJSPsandturnsthemintoservletsourcecode.TheseconddevelopsJSPsasXMLdocuments.
PrecompilingJSPs
PrecompilingaJSPinvolvesusingaserver-providedcommand-linetooltoconverttheJSPpageintoaservletclassfile.AJSPisconvertedintoaservlet,oftencalledaJavaServerPageimplementationclass,beforeithandlesanyHTTPrequests.TheJSPspecificationreferstothestagebywhichtheJSPcontainerconvertsJSPpagesyntaxintoaservletasthetranslationphase.InTomcat,ifyouwanttoexaminewhattheJSPpageimplementationclasslookslikeafterthisconversion,gotothisdirectory:
Tomcat-install-directory/work/Standalone/name-of-host/name-of-web-app
name-of-hostcouldbelocalhost,oranyotherhostnamethatreferstotheserverTomcatisinstalledon.Thenameofthewebapplicationisalsothenameofthecontext;thisisusuallysomethinglikeexamples,ROOT,orstorefront.
Theindicateddirectorycontains.javafiles,suchasdefault_jsp.java.ThesearetheJavasourcefilesthatarecompiledintoclassfiles,andthenexecutedasservletstorespondtorequests.
ThereasonswhyaJSPdevelopermaywanttoprecompileaJSPpageinclude:
1. AvoidingtheperceptibledelaycausedwhenaJSPisfirstrequestedfromthewebcontainer,duringwhichtheJSPcompilerconvertstheJSP'ssourcecodeintoaservlet.
AllowingthedevelopertoexaminetheJavasourcecodefortheJSPpageimplementationclass,andoptionallyworkonthecodewiththeirservletIDE'ssourcecodeeditor.
InbothTomcatandWebLogic,acommand-linetoolcanbeusedtoprecompileaJSP.Recipe5.4coversthemappinginweb.xmlofaJSPpagetoitsservletimplementationclass.
JSPsasXMLDocuments
ThelaterrecipesinthischapterdescribecreatingJSPsasXMLfiles.BoththeJSPspecificationsv1.2and2.0describethegenerationanduseofJSPsaspureXMLdocuments.ThismeansthatratherthancreateJSPsintypicalJSPpagesyntax,theyareinsteadcodedaswell-formedXMLdocuments.AccordingtotheJSPspecification,aJSPdocumentisanamespace-awareXMLdocument.TheJSPcontainerdifferentiatesJSPdocumentsfromtraditionalJSPpagesinatleastoneofthreeways.
1. Ajsp-property-groupelementinweb.xmlspecifiesaJSPdocumentwiththeis-xmlchildelement.(Thejsp-property-groupelementisoneoftheJSPconfigurationelementsthattheJSP2.0specificationhasproposedaddingtoweb.xml.)
Thefilehasa.jspxextension.
TheJSPpagehasarootelementofjsp:root.
Recipe5.5showswhatthesefileslooklike.
TheJSPspecificationdescribesanXMLviewasadescriptionofaJSPpageinXMLform.AnXMLviewisgeneratedbytheJSPcontainerduringthetranslationphase.Asubclassofjavax.servlet.jsp.tagext.TagLibraryValidatorcanusetheXMLviewtoparseaJSPinordertovalidatethatcustomtagshavebeenusedcorrectly,beforethecontainerfinallyconvertstheJSPintoitspage
implementationclass(aservlet).Recipe5.6showshowtogenerateXMLviewsforaJSP,andhowtosavetheresultingXMLfiles.
JSPscanbecreatedasXMLfilesforthefollowingreasons,amongothers:
WebcontainerscanacceptJSPdocumentsinwebapplications,meaningthatthewebapplicationcancontainXMLfilesinsteadofthepagesintraditionalJSPsyntax.JSPdocumentscanthusbeintegratedwithotherXMLcontent,suchasXHTMLfiles,ScalableVectorGraphics(SVG),andtheXMLfilesthatarepartofwebservicestransactions.
YoucanuseXMLeditorstoworkwithJSPdocuments.
YoucanuseotherXMLtechnologieswithJSPdocuments,suchasXSLT,SimpleObjectAccessProtocol(SOAP),SAX,andDOM.
Recipe5.1PrecompilingaJSPinTomcat
Problem
YouwanttoconvertJSPsintoservletsusingTomcat4.1.x.
Solution
UsetheJspCcommand-linetoolfoundin<Tomcat-installation>/bin.
Discussion
UsingtheJspCcommand-linetoolisthefirststepinprecompilingTomcatJSPs.Thistoolisofferedintheformofashellscriptjspc.shonUnixsystemsandjspc.batonWindowsandcreatestheJavasourcefilesfortheJSPpageimplementationclasseswithwhichitissupplied.Theresultant.javafilesstillhavetobecompiledintoservletclassfiles,usingjavacoranotherJavacompiler.SinceprecompilingJSPsisatwo-stepprocess,Irecommendabatchfileforconvenience.However,let'sfirstexaminehowtousetheJspCutility.
TheWindowsshellscriptforrunningJspC(<Tomcat-install-directory>/bin/jspc.bat)requiresthataJASPER_HOMEenvironmentvariablebesettotheTomcatinstallationdirectory.Setthisenvironmentvariablewiththefollowingcommandline:
setJASPER_HOME=k:\jakarta-tomcat-4.1.12
RuntheJspCutilitybychangingtothe%JASPER_HOME%\bindirectoryandtypingthefollowingcommand(specifyyourowndirectorypathsandissuethecommandononeline):
jspc-dH:\book\cookbook-webincH:\book\cookbook\map.xml
-webapph:\book\cookbook\dist
The-dswitchspecifiesthedirectorywhereyouwouldlikethesourcefilestobegenerated,andthe-webincswitchspecifiesthenameofanautomaticallygeneratedfilewhereJspCwillcreatetheservletandservlet-mappingelementsfortheservletfiles.IfyoucompileaJSPpagethatiscalledprecomp.jsp,themappingswouldlooklikeExample5-1.
Example5-1.ServletmappingforaprecompiledJSP
<servlet>
<servlet-name>org.apache.jsp.precomp_jsp</servlet-name>
<servlet-class>org.apache.jsp.precomp_jsp</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>org.apache.jsp.precomp_jsp</servlet-name>
<url-pattern>/precomp.jsp</url-pattern>
</servlet-mapping>
Youcanthencutandpastetheseservletandservlet-mappingelementsintotheweb.xmldeploymentdescriptorforyourwebapplication.
The-webappswitchspecifiesaweb-applicationdirectory,whichmustinturnhavea/WEB-INFsubdirectorycontainingyourapplication'sweb.xmlfile.JspCfindsallofthe.jspfilesatthetoplevelofthisweb-applicationdirectoryandtranslatesthemintoservletsourcefiles,alongwithanyJSPsinnestedsubdirectories.Theresulting.javafilesareplacedinthedirectoryspecifiedwiththe-dswitch.Unlike-webinc,the-webxmlswitchcreatesanentireweb.xmlfilethatincludesthenewservletsandservletmappings.SeveralotherJspCoptionsaredescribedhere:http://cvs.apache.org/viewcvs/~checkout~/jakarta-tomcat-4.0/jasper/doc/jspc.html.
You'llthenneedtocompilethegeneratedsourcefiles.Irecommendusingabatchfiletotakecareofbothstepsatonce.TheWindowsbatchfileinExample5-2generatesthesourcefilesandusesthejavactooltocompiletheservlets.
Example5-2.UsingabatchfiletoprecompileJSPswithTomcat
@echooff
jspc-dH:\book\cookbook\classes-webincH:\book\cookbook\map.xml-webapph:\book\
cookbook\dist
setPRECLASSPATH=%CATALINA_HOME%\common\lib\servlet.jar;
%CATALINA_HOME%\common\lib\jasper-runtime.jar;%CLASSPATH%
javac-classpath%PRECLASSPATH%-d./classes*.java
Savethisfileinatextfilewithanamelikeprecomp.bat.Changetothedirectorycontainingthebatchfileandtypeprecomp.ThisbatchfilerunstheJspCcommandonall.jspfilesexistingbeneaththeh:\book\cookbook\distweb-applicationdirectory.Usingthe-webincswitch,thecommandcreatesanXMLfragmentofservletandservlet-mappingelementsasshownearlierinthisrecipe.Iftherearenoproblems,thecompiledfileswillbestoredintheh:\book\cookbook\classesdirectory.
ThecodethencreatesaPRECLASSPATHenvironmentvariablethatincludestheservlet.jarandjasper-runtime.jarcomponents,alongwithanydirectoriesorJARsthatarepartoftheexistingCLASSPATHenvironmentvariable.Theservlet.jarcomponentisnecessarytoimporttheseJavapackagesduringcompilation:
javax.servlet
javax.servlet.http
javax.servlet.jsp
Addingthejasper-runtime.jarisnecessarytoimporttheorg.apache.jasper.runtimepackage.OnWindows,youmayhavetosetaJASPER_HOMEenvironmentvariabletotheTomcatinstallationdirectorybeforethisbatchfilerunsproperly.
Example5-3showsaUnixshellscriptthataccomplishesthesametask.Thisscriptexecutesthejspc.shfileinTomcat's/bindirectory,precompilingalloftheJSPfilesthattheJspCtoolfindsinthecurrentworkingdirectory.Thescriptstorestheresulting.javafilesinthe./classesdirectory.
Example5-3.AshellscriptforprecompilingJSPfiles
#!/bin/sh
$CATALINA_HOME/bin/jspc.sh-d./classes-webinc./map.xml-webapp./;
PRECLASSPATH=$CATALINA_HOME/common/lib/servlet.jar:$CATALINA_HOME/common/lib/jasper-
runtime.jar;
exportPRECLASSPATH;
javac-classpath$PRECLASSPATH-d./classes./classes/*.java
SeeAlso
Recipe5.3ontheprecompilationprotocol;Recipe5.4onmappingthecompiledJSP(s)inweb.xml;theJSPprecompilationsectionofJavaServerPagesbyHansBergsten(O'Reilly);ChapterJSP.11.4oftheJSP2.0specification.
Recipe5.2PrecompilingaJSPinWebLogic
Problem
YouwanttoprecompileaJSPinWebLogic.
Solution
Usetheweblogic.jspcJavautilitythatinstallswithWebLogicServer7.0.
Discussion
WebLogicServer7.0installswithitsownJavautilityforprecompilingJSPs:weblogic.jspc.ThisutilityispartoftheJARfilethatcanbefoundatthislocation:<WebLogic-install-directory>/weblogic700/server/lib/weblogic.jar.WhenyouprecompileJSPsusingweblogic.jspc,itplacestheclassfilesinthespecifieddestinationdirectory.Example5-4showsasimplebatchfileonWindowsNTthatprecompilesanexample.jspJSPpageintoitsservletimplementationclass.
Example5-4.PrecompilingaJSPwithweblogic.jspc
@echooff
setWLCLASSPATH=k:\bea\weblogic700\server\lib\weblogic.jar;%CLASSPATH%
java-cp%WLCLASSPATH%weblogic.jspc-d.\classesexample.jsp
ThesecondlineofExample5-4setsanenvironmentvariable,WLCLASSPATH.Thisvariableprependsareferencetoweblogic.jartotheexistingCLASSPATHvariable.Thenextlineoftheexampleusesthis
combinedclasspathtorunweblogic.jspc.The-dswitchtellstheprogramwheretostoretheresultingclassfiles,inthiscase,intheclassesdirectorybeneaththedirectorycontainingthebatchfileandexample.jsp.ThisprogramgeneratesaJavaclassfilenamedjsp_servlet.__example.class(includingthepackagename).Ifyoudonotspecifyapackageforthecompiledservlet,jsp_servletisusedasthedefaultpackagename(seeExample5-6).Example5-5showsashellscriptthatiswrittenonMacOSXforprecompilingaJSPwithWebLogic.
Example5-5.PrecompilingJSPswithweblogic.jspcandashellscript
#!/bin/sh
WLCLASSPATH=/Users/bruceper/java/weblogic_jar/weblogic.jar:$CLASSPATH;
exportWLCLASSPATH;
java-cp$WLCLASSPATHweblogic.jspc
-d/Users/bruceper/books/cookbook/code/chap5/classesnewfile.jsp
weblogic.jspcisdifferentfromTomcat'sJspCutilityinthatitcompilesafileinJSPpagesyntaxintotheservletclassfileinasingleoperation.UsingTomcat'sJspCfromthecommandlinerequirestheuseofacompiler,suchasjavac,tocompilethe.javafilesgeneratedbyJspCintoclassfiles.ThissecondcompilationstepwhenusingJspCishandledautomaticallywhenusingweblogic.jspc.
TheWindowsbatchfileinExample5-6specifiesajspservletcookbookpackageforalltheJSPpagesfoundinthewebapplicationspecifiedbythe-webappswitch.
Example5-6.Usingweblogic.jspctoprecompileallJSPpagesinawebapplication
@echooff
setWLCLASSPATH=k:\bea\weblogic700\server\lib\weblogic.jar;%CLASSPATH%
java-cp%WLCLASSPATH%weblogic.jspc-d.\classes-packagejspservletcookbook-compileAll
-webapph:/home
Example5-7showsaUnixshellscriptthatdoesthesamething.
Example5-7.PrecompilingallJSPpagesinawebapplicationwithashellscript
#!/bin/sh
WLCLASSPATH=/Users/bruceper/java/weblogic_jar/weblogic.jar:$CLASSPATH;
exportWLCLASSPATH;
java-cp$WLCLASSPATHweblogic.jspc-d/Users/bruceper/books/cookbook/code/chap5/classes
-packagejspservletcookbook-compileAll-webapp/Users/bruceper/books/cookbook/code/chap5
Notethisportionoftheinstructionintheexample:
-compileAll-webapph:/home
The-compileAllswitch,alongwithanargumentto-webapp,tellsweblogic.jspctoprecompilealltheJSPfilesfoundinthewebapplicationconfiguredintheh:\homedirectory,includinganyJSPfilesnestedinsubdirectories.Thiswebapplicationisinexplodeddirectoryformat(notarchivedintoaWARfile).InExample5-6,thecompiledclassesarestoredinthe\classes\jspservletcookbookdirectorypath.
SeeAlso
Recipe5.3ontheprecompilationprotocol;Recipe5.4onmappingthecompiledJSP(s)inweb.xml;theJSPprecompilationsectionofJavaServerPagesbyHansBergsten(O'Reilly);ChapterJSP.11.4oftheJSP2.0specification.
Recipe5.3PrecompilingJSPswiththePrecompilationProtocol
Problem
Youwanttousethe"precompilationprotocol"thatispartoftheJSPspecificationtoprecompileoneormoreJSPfiles.
Solution
SendarequesttotheJSPcontainerthatincludesajsp_precompileparameter.
Discussion
TheJSP1.2and2.0specificationsrequirecompliantJSPcontainerstosupporttheuseofthejsp_precompilerequestparameter.ThisparametersuggeststhatthecontainerprecompiletherequestedJSP.HereishowitworksinTomcat:
1. RequesttheJSPthatyouwantprecompiledwiththejsp_precompileparameteraddedtotheURL,asinhttp://localhost:8080/home/url_rewrite.jsp?jsp_precompile=true.
TheJSPcontainerisnotsupposedtoexecutetheJSPpage;itjustprecompilesit.Theresultoftherequest,ifyouweremakingitinawebbrowser,isablankpage.
IftheJSPfileinJSPpagesyntaxhasnotyetbeencompiled,oriftheJSPfilehasbeenchangedandhasalatermodificationdatethanany
existingpageimplementationclass,TomcatcreatesanewJavasourceandclassfilefortheJSPinthe<Tomcat-install-directory>/workdirectory.IftheJSPfileisnamedurl_rewrite.jsp,TomcatcallstheJavasourceandclassfilesurl_rewrite_jsp.javaandurl_rewrite_jsp.class.
Supplyingtherequestparameterjsp_precompile(withoutthe"=true"part)isthesameasrequestingjsp_precompile=trueintheURL.
TheprecompilationprotocolinTomcatwillbothcreatethe.javafileandcompilethatfileintotheJSPpageimplementationclass.UsingtheJspCtoolasdescribedinRecipe5.1willgenerateonlya.javafile.
ThisprotocolisbestusedwithanautomatedtoolthatcanmakeHTTPrequests,suchastheJakartaCommonsHttpClientcomponent.UsingsuchatoolallowsyoutoautomatetheprecompilationofdozensofJSPsbysendingseveralHTTPrequestsfromasingleJavaprogram.
SeeAlso
Recipe5.1onusingTomcat'sJspCutility;Recipe5.2onprecompilingwithWebLogicServer;Recipe5.4onmappingthecompiledJSPsinweb.xml;Chapter7onsendingHTTPrequestsfromaservletoraJSP;theJakartaCommonsHttpClienthomepageathttp://jakarta.apache.org/commons/httpclient/;TheJSPprecompilationsectionofJavaServerPagesbyHansBergsten(O'Reilly);ChapterJSP.11.4oftheJSP2.0specification.
Recipe5.4MappingaJSPtoItsPageImplementationClass
Problem
YouhavealreadyprecompiledaJSPandwanttospecifyamappingtotheJSPpageimplementationclassinyourdeploymentdescriptor.
Solution
Cutandpastetheservletandservlet-mappingelementsgeneratedautomaticallybyJspCintoweb.xml.Createtheproperpackage-relateddirectoriesintheWEB-INF/classesdirectoryofyourwebapplication,thenplacetheprecompiledJSPsintothatdirectory.
Discussion
PrecompilingJSPsallowsyoutoremovetheJSPpagesyntaxfilesfromyourwebapplicationandjustusetheresultingservletclassfiles.Youcanthenusetheservlet-mappingelementinweb.xmltomapaJSP-styleURL(e.g.,default.jsp)tothecompiledservletclass.Hereishowtoaccomplishthistask:
1. PrecompiletheJSP(s)asdescribedinRecipe5.1orRecipe5.2,includingthecompilationofJavasourcefilesintoclassfilesusingjavacoranothercompilertool.
Cutandpastetheservletandservlet-mappingelementsgeneratedautomaticallybyJspCintoyourdeploymentdescriptor(ifyouareusingTomcat),oraddthoseelementsmanuallytoweb.xml(ifyouare
usingWebLogicoranothercontainer).
Makesuretheservlet-mapping'surl-patternelementpointstoaJSP-stylefilename,suchasdefault.jsp,oranextensionmappingsuchas*.jsp.
Placetheclassorclasses,includingthepackage-relateddirectories,inWEB-INF/classes,orinsideofaJARfilethatisstoredinWEB-INF/lib.
WhenthewebusersrequesttheURLspecifiedbytheservlet-mappingforthatJSPpageimplementationclass,thewebcontainerwillnowdirectthatrequesttothemappedservletclass.
Example5-8showsaservletconfigurationforaprecompiledJSP.
Example5-8.Aweb.xmlentryforaprecompiledJSP
<servlet>
<servlet-name>org.apache.jsp.precomp_jsp</servlet-name>
<servlet-class>org.apache.jsp.precomp_jsp</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>org.apache.jsp.precomp_jsp</servlet-name>
<url-pattern>/precomp.jsp</url-pattern>
</servlet-mapping>
Thedirectorystructureforthisclassinyourwebapplicationshouldbesomethinglike:/WEB-INF/classes/org/apache/jsp/precomp_jsp.class.Ifthecontextpathforyourwebapplicationis/home,userscanrequestthisJSP'simplementationclass(aservlet,behindthescenes)withaURLsimilartohttp://localhost:8080/home/precomp.jsp.
SeeAlso
Recipe5.1-Recipe5.3;ChapterJSP.11.4oftheJSP2.0specification.
Recipe5.5CreatingaJSPfromScratchasaJSPDocument
Problem
YouwanttocreateaJSPdocumentinanXMLeditor'stool.
Solution
OpenupyourXMLeditorofchoiceandcreatetheJSPusingonlyXMLelements.
Discussion
AJSPdocumentisanamespace-aware,well-formedXMLfilethatcontainsJSPstandardactions(suchasjsp:includeandjsp:useBean),customactions(suchasJSTLcustomtags),andtheXMLequivalentsofJSPdirectives.Table5-1specifiestheXMLequivalentsforcommonJSPdirectives.WritetheJSPdocumentinanXMLeditor,preferablyonewhereyoucancheckitswell-formedness.TheJSPdocumenthastobeawell-formedXMLdocumenttobeeligibleforplacementintoaJSPcontainerandexecution.
Table5-1.XMLequivalentsforJSPdirectives
Directive Example JSPdocumentequivalent
<page><%@pageimport="java.util.Date"%> <jsp:directive.pageimport="java.util.Date"/>
<include><%@includefile="footer.html"%> <jsp:directive.includefile="footer.html"/>
<taglib>
<%@tagliburi="WEB-INF/tlds/xml_gen.tld"prefix="t"%>
<jsp:rootjsp:id="0"xmlns:jsp="http://java.sun.com/JSP/Page"version="2.0"xmlns:t="urn:jsptld:/WEB-INF/tlds/xml_gen.tld">
InJSP1.2,theonlywaytoidentifyaJSPpageasXMLisbyhavingajsp:rootelementastheroot.However,JSP2.0offersseveralnewoptionstheJSP2.0specificationstatesthataJSPdocumentcanalsobedistinguishedfromaJSPinnon-XMLsyntaxbyajsp-property-groupelementinthedeploymentdescriptor,a.jspxfileextension,orajsp:rootrootelement.
ThisrecipeshowsasimpleJSPpageanditsXMLequivalent,thenrepeatsthecomparisonwiththeadditionofacustomtagandaruntimeexpressionforaJSPelementattribute.Example5-9isasimplefileinJSPpagesyntaxshowingthewebserver'slocaltime.
Example5-9.AsimpleJSPpage-syntaxfile
<%@pagecontentType="text/html"%>
<%@pageimport="java.util.Date"%>
<html>
<head><title>WelcometotheWeb</title></head>
<body>
<h2>WelcometotheWeb</h2>
Theserver'slocaltimeis<%=newDate()%>.
</body>
</html>
ThisJSPhastwopagedirectivesandaJSPexpressionthatdisplaysadateandtimestringonthebrowserpage.Figure5-1showstheexecutionofthispageinabrowser.
Figure5-1.SimpleJSPbeforeXMLconversion
ThispagecanbeconvertedintoaJSPdocumentbycuttingandpastingthecodeintoanXMLeditorandreplacingnon-XMLconstructswithXMLelements.Example5-10istheJSPdocumentequivalentofExample5-9.
Example5-10.AsimpleJSPdocumentaswell-formedXML
<jsp:rootxmlns:jsp="http://java.sun.com/JSP/Page"version="2.0">
<jsp:directive.pagecontentType="text/html"/>
<jsp:directive.pageimport="java.util.Date"/>
<html>
<head><title>WelcometotheWeb</title></head>
<body>
<h2>WelcometotheWeb</h2>
Theserver'slocaltimeis<jsp:expression>newDate()</jsp:expression>.
</body>
</html>
</jsp:root>
Example5-10hasjsp:directive.pageelementsinsteadoftraditionalJSPdirectives,whicharenotvalidXMLelementsbecauseofthe<%@syntax.AnythinginaJSPpagethatuses<%-styledelimiterscannotbeusedtodistinguishJSPelements,becausethentheJSPdocumentwillnotpassanXMLwell-formednesstest.
Example5-11isamorecomplexJSPpagewithataglibdirectivethatspecifiesthecoretaglibraryfromJSTL1.0;thepagealsouses
ExpressionLanguage(EL)code.Further,thepagehasajsp:useBeanelementthatsetsajava.util.DatevariabledateStringtopagescope.
Example5-11.AJSPpagepresentingacomplexXMLconversion
<%@pagecontentType="text/html"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>WelcometotheWeb</title></head>
<body>
<h2>WelcometotheWeb</h2>
Hello,<c:outvalue="${param.firstName}${param.lastName}"/><br><br>
<jsp:useBeanid="dateString"class="java.util.Date"/>
Thetimeis<c:outvalue="${dateString}"/>.<br><br>
Thevalueof10+24+35=<c:outvalue="${10+24+35}"/>
</body>
</html>
Example5-12isthesameJSPpageconvertedtoaJSPdocument.
Example5-12.Referringtotaglibraries(taglibs)inaJSPdocument
<jsp:rootxmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:c="http://java.sun.com/jstl/core"version="2.0">
<jsp:directive.pagecontentType="text/html"/>
<html>
<head><title>WelcometotheWeb</title></head>
<body>
<h2>WelcometotheWeb</h2>
<jsp:text>Hello</jsp:text>
<c:outvalue="${param.firstName}${param.lastName}"/><br></br><br></br>
<jsp:useBeanid="dateString"class="java.util.Date"/>
<jsp:text>Thetimeis</jsp:text><c:outvalue="${dateString}"/>.
<br></br><br></br>
<jsp:text>Thevalueof10+24+35=</jsp:text>
<c:outvalue="${10+24+35}"/>
</body>
</html>
</jsp:root>
InaJSPdocument,anytaglibrariescanbeincludedasnamespaceattributes,suchasinthejsp:rootelement,asshownhere:
<jsp:rootxmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:c="http://java.sun.com/jstl/core"version="2.0">
Thejsp:textelementcanbeusedtocontainanytemplatedataintheJSPdocument.YoucanusetheJSPstandardactionssuchasjsp:useBeanandcustomtagslikec:outwiththesamesyntaxusedinaJSPpage.
Figure5-2showsthebrowseroutputoftheJSPdocumentinExample5-12.ThispagewasrequestedbyusingthisURL:http://localhost:8080/home/example_xml2.jsp?firstName=Bruce&lastName=Perry.
Figure5-2.OutputfromExample5-11
HereiswhattheHTMLsourcecodelookslike,ifyouchose"ViewSource"fromthebrowsermenu(withsomecarriagereturnsaddedforreadability):
<html><head><title>WelcometotheWeb</title></head>
<body>
<h2>WelcometotheWeb</h2>
HelloBrucePerry<br/><br/>
ThetimeisMonFeb1016:20:05EST2003.<br/><br/>
Thevalueof10+24+35=69
</body></html>
SeeAlso
Recipe5.6ongeneratinganXMLviewfromaJSP;ChapterJSP.6(JSPdocuments)oftheJSP2.0specification;ChapterJSP.10(XMLviews)oftheJSP2.0specification.
Recipe5.6GeneratinganXMLViewfromaJSP
Problem
YouwanttoautomaticallygenerateanXMLviewfromaJSPpage.
Solution
CreateacustomtagandaTagLibraryValidatorclass,fromwhichyoucanoutputtheXMLviewofaJSPtoafile.
Discussion
AnXMLviewisanXMLformofaJSPpagethattheJSPcontainergeneratesduringthetranslationphase,anintermediarystagebeforethecontainerconvertstheJSPtoitspageimplementationclass(aservlet).ATagLibraryValidatorclasscanusetheXMLviewtovalidatetheuseofcustomtagsintheJSPpriortotheJSP'sconversiontoaservlet.AnXMLviewisverysimilartoaJSPdocument,whichisanXMLformofaJSPpagethatJSPdeveloperscanwriteandaddtotheirwebapplications.ThedifferencesbetweenthetwoXMLfilesaccordingtotheJSPspecificationv2.0are:
AnXMLviewexpandsanyincludedirectivesthataJSPdocumentcontainsintotheircorrespondingJSPfragments.
AnXMLviewprovideseachXMLelementwithajsp:idattribute.
AnXMLviewaddsajsp:rootelementastherootelementofthedocumentifthedocumentdoesnotalreadyhaveajsp:root
element.
AnXMLviewaddsajsp:directive.pageelementandpageEncodingattributeiftheydonotalreadyexist,andsetsthevalueofpageEncodingto"UTF-8".
AnXMLviewaddsajsp:directive.pageelementandcontentTypeattributeiftheydonotalreadyexist,andsetsthevalueofcontentTypeaccordingtoChapterJSP.4.2,"ResponseCharacterEncoding,"oftheJSP2.0specification(e.g.,"text/xml"foraJSPdocument).
Javadeveloperscanaddsubclassesofjavax.servlet.jsp.tagext.TagLibraryValidatortotheirwebapplicationsastoolsforvalidatingtheapplication'suseofcustomtags.TheJSPcontainer(JasperisthenameoftheTomcatJSPcontainer)makesavailabletotheTagLibraryValidatoranXMLviewofaJSPpageforthepurposeofparsingXMLelementsinthepageandvalidatingwhetherornottheyhavebeenusedcorrectly.
ItisusefultoexaminetheXMLviewofaJSPpageinordertodebugaTagLibraryValidatorclassthatyouareusinginacustomtaglibrary,ortoopenupyourJSPinanXMLeditorandevaluateitssyntaxfromanXMLperspective.Hereisaniceway(okay,abitofahack!)toautomaticallygenerateafilerepresentingtheXMLviewofaJSPpage.Thisrecipeusesajavax.servlet.jsp.tagext.PageDataobject,whichautomaticallyreturnstheXMLviewofaJSPpageasajava.io.InputStream.Hereishowitworks:
1. Createaclassthatextendsjavax.servlet.jsp.tagext.TagLibraryValidator.Theseclassesareusedtovalidatetheuseofcustomtags,andareexplainedinmoredetailinChapter23.
OverridetheTagLibraryValidator.validate(Stringprefix,Stringuri,PageDatapage)methodtowritetheXMLview
informationfromthePageDataparametertoafile.
Createasimplecustomtagbyextendingjavax.servlet.jsp.tagext.TagSupport.Thistag"marks"aJSPpagesothatitsXMLviewcanbeoutputtoafile.Thetagincludesa"filename"attributefromwhichyourvalidatorclasswillgetthefilenamefortheXMLview.Thetaglookslikethis:
<t:toxmlfilename="myxml_view"/>
CreateaTagLibraryDescriptor(TLD)fileforthistaglibrary,specifyingtheTagLibraryValidatorclassyoucreatedasthevalidatorforthislibrary:
<validator>
<validator-class>
com.jspservletcookbook.ToXmlValidator
</validator-class>
<description>
SavesXMLviewsofJSPpagestothe
specifieddirectory.
</description>
</validator>
PlaceboththeTagLibraryValidatorandtheTagSupportclassesintheWEB-INF/classesdirectoryofthewebapplication,orinsideaJARfilethatisstoredinWEB-INF/lib(theexamplesinthisrecipeassumethisformat,ratherthanplacingtheclassesinaJAR).
PlacetheTLDfileintheWEB-INF/tldsdirectory.
AddataglibelementreferringtoyourtagsandTLDtotheWEB-INF/web.xmldeploymentdescriptor.
Thetaglibelementinweb.xmlisnotneededwithJSPVersion1.2and2.0,sincetheJSPcontainerautomaticallysearchesWEB-INF,aswellastheMETA-INF
directoryofyourapplication'sJARfiles,foranyfilethatendswiththeextension.tld.
8. CreateapropertiesfilecontainingthedirectorypaththatyouwanttousefortheautomaticallygeneratedXMLview.StorethispropertiesfileinWEB-INF/classesusingtheappropriatepackagenames.Thispropertiesfileisusedtoavoidthehardcodingofanabsolutedirectoryinthevalidatorclass'scode.
UsethecustomtagintheJSPfile(s)forwhichyouwanttheXMLviewsgeneratedasfiles.
First,Example5-13showstheXMLview-relatedcustomtaginaJSPfile.
Example5-13.GeneratingtheXMLviewofaJSPpage
<%@tagliburi="/toxml_view"prefix="t"%>
<html>
<head>
<title>Testtld</title>
</head>
<bodybgcolor="#ffffff">
Hello,thispageisusingthetoxmltagtolookatitsXMLView.
<t:toxmlfilename="my_xmlview"/>
</body>
</html>
Thet:toxmltagisanemptyelementthatsignalsthevalidatorclasstogenerateafilecontaininganXMLview.Thefilewillbenamedmy_xmlview.xml(thevalidatorclassaddsthe.xmlextension).Thetag
otherwisehasnoeffectontheappearanceorbehaviorofthisJSP.ThefollowingfragmentofthedeploymentdescriptorshowsthetaglibelementspecifyingtheURIthatisusedinExample5-11staglibdirective.ThetaglibelementinthedeploymentdescriptoralsospecifiesthelocationoftheTLDfile(WEB-INF/tlds/xml_gen.tld):
<taglib>
<taglib-uri>/toxml_view</taglib-uri>
<taglib-location>/WEB-INF/tlds/xml_gen.tld</taglib-location>
</taglib>
Example5-14showstheTLDfileforthistaglibrary,whichspecifiesthevalidatorclassandthesimplecustomtag(amarker)usedinExample5-11.Iamnotgoingtoshowthecodeforthetoxmltag,sinceitdoesnotcontainanycodeofinterest,beyondthefactthatithasoneStringmembervariablecalledfilename.Thesolepurposeofthetag'suseistoputthevalidatorclasstowork.TheJSPcontainercreatesonevalidatorinstanceforeachtaglibrarythatincludesavalidatorclass.
Example5-14.TheTLDfilefortheXMLviewcustomtag
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEtaglib
PUBLIC"-//SunMicrosystems,Inc.//DTDJSPTagLibrary1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>Validatortest</short-name>
<description>Validatortest</description>
<validator>
<validator-class>
com.jspservletcookbook.ToXmlValidator
</validator-class>
<description>
SavesXMLviewsofJSPpagestothespecified
directory.
</description>
</validator>
<tag>
<name>toxml</name>
<tag-class>com.jspservletcookbook.ToXml</tag-class>
<body-content>EMPTY</body-content>
<description>
ThistagdemonstratestheproductionofJSPXMLviewfiles.
</description>
<attribute>
<name>filename</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
<description>
Thisattributeprovidesthefilename.</description>
</attribute>
</tag>
</taglib>
Thecom.jspservletcookbook.ToXmlValidatorclass,thelibrary'svalidator,executesitsvalidatemethodwhenaJSPpageusingthetoxmltagisloaded.HowdoesthevalidatorclassknowwheretosavethefilesrepresentingtheJSP'sXMLview?Thecom.jspservletcookbook.ToXmlValidatorclassderivesthedirectorypathforsavingitsgeneratedfilesfromthepropertiesfileshownbelow.ThisallowsanydeployerofthecustomtagtochangethedirectoryforthesavedXMLviews,withouttouchingthevalidatorclass'ssourcecode.Thepropertiesfileislocatedinthesamedirectoryasthevalidatorclass.ThepathtothispropertiesfileisWEB-INF/classes/com/jspservletcookbook/validator.properties:
directory=h:/home/xmlviews
Thefilenameisprovidedbythetagitself,asin:
<t:toxmlfilename="my_xmlview"/>
TheentirefilepathfortheXMLviewlookslike:h:/home/xmlviews/my_xmlview.xml.
Thevalidatorclassaddsthe.xmlextensionwhenitcreatestheXMLviewfile.ThevalidatorfirstextractsthefilenamefromthetoxmltagbyusingaSAXparsertoparsetheinputstreamfromthejavax.servlet.jsp.tagext.PageDataobject.
Younowhaveallofthepiecestogetherexceptfortheall-importantvalidatorclass,whichisshowninExample5-15.Thevalidatemethodreadsthedirectorypropertyvalueusingajava.util.ResourceBundleobject.ThevalidatemethodgetsthefilenamebyusingthehelperclassthatExample5-16shows.ThevalidatemethodthengeneratestheXMLviewoftheJSPpagebyusingthejava.io.InputStreamreturnedfromPageData.getInputStream().
Example5-15.AvalidatorclassforgeneratingXMLviewfiles
packagecom.jspservletcookbook;
importjavax.servlet.jsp.tagext.TagLibraryValidator;
importjavax.servlet.jsp.tagext.ValidationMessage;
importjavax.servlet.jsp.tagext.PageData;
importjava.io.*;
importjava.util.ResourceBundle;
importjava.util.MissingResourceException;
importjava.util.Date;
publicclassToXmlValidatorextendsTagLibraryValidator{
/**CreatesnewToXmlValidator*/
publicToXmlValidator(){
}
publicValidationMessage[]validate(java.lang.Stringprefix,
java.lang.Stringuri,PageDatapage){
ValidationMessage[]vam=null;
try{
ResourceBundlebundle=
ResourceBundle.getBundle("com.jspservletcookbook.validator");
Stringdirectory=bundle.getString("directory");
StringfileName=getFilename(page);
//throwanExceptionifthedirectoryisinvalid
if(directory==null)
thrownewException(
"ReceivedanulldirectoryfortheXMLviewfile.");
//throwanExceptionifthefilenameisinvalid
if(fileName==null)
thrownewIOException(
"ReceivedanullfilenamefortheXMLviewfile.");
Filefile=newFile(directory+"/"+fileName+".xml");
FileWriterwriter=newFileWriter(file);
BufferedReaderin=newBufferedReader(
newInputStreamReader(page.getInputStream()));
Stringline="";
//writetheXMLviewtothespecifiedfile
while((line=in.readLine())!=null){
writer.write(line);
}
in.close();
writer.close();
}catch(IOExceptionio){
//returnavalidationmessage
ValidationMessagevmsg=new
ValidationMessage(null,io.getMessage());
vam=newValidationMessage[1];
vam[0]=vmsg;
returnvam;
}catch(MissingResourceExceptionmre){
//returnavalidationmessage
ValidationMessagevmsg=new
ValidationMessage(null,mre.getMessage());
vam=newValidationMessage[1];
vam[0]=vmsg;
returnvam;
}catch(Exceptione){
//returnavalidationmessage
ValidationMessagevmsg=new
ValidationMessage(null,e.getMessage());
vam=newValidationMessage[1];
vam[0]=vmsg;
returnvam;
}
//returnemptyarray
vam=newValidationMessage[0];
returnvam;
}
privateStringgetFilename(PageDatapage)throwsException{
try{
ValidateHandlerhandler=newValidateHandler();
returnhandler.getFilename(page);
}catch(Exceptione){
throwe;}
}
}
Example5-16showstheValidateHandlerhelperclassthatourvalidatorusestogetthefilenamefromthecustomtag.TheValidateHandlermakesafirstpassthroughtheXMLview(beforeitiswrittentoafile)toextractthefilenamethattheuserhasaddedwiththetoxmlelement'sfilenameattribute.TheValidateHandlerdoesalltheworkbehindthescenestoparsetheXMLsothatthevalidatorclasscangetthefilenamewithasimplemethodcall:
ValidateHandlerhandler=newValidateHandler();
returnhandler.getFilename(page);
TheValidateHandlerusestheJavaAPIforXMLprocessing(JAXP)andtheSimpleAPIforXML(SAX)toparsetheXMLprovidedbyjavax.servlet.jsp.tagext.PageData.getInputStream().YouhavetoplacetheValidateHandlerclassinsideoftheWEB-INF/classesdirectory(orinsideofaJARfileinWEB-INF/lib)sothatyourwebapplication(theToXmlValidatorclass)canfindit.YoucanuseanycomponentyouwanttoprovidetheSAXfunctionalitythatawebapplicationneeds.IfyouchoosetouseJAXP,andyourwebcontainerisnotyetbundledwiththenecessaryJAXPcomponents,thenaddthefollowingJARfilestoyourWEB-INF/libdirectoryforacompleteJAXPinstallation:jaxp-api.jar,dom.jar,sax.jar,xalan.jar,xercesImpl.jar,andxsltc.jar.YoucandownloadthesecomponentsaspartoftheJavaWebServicesDeveloperPack(http://java.sun.com/webservices/webservicespack.html),andtheJAXPlibrariesareincludedaspartofJava1.4.x.
Example5-16.ADefaultHandlerthatgrabsthefilenamefromthecustomtagattribute
importorg.xml.sax.Attributes;
importorg.xml.sax.SAXParseException;
importorg.xml.sax.SAXException;
importorg.xml.sax.helpers.DefaultHandler;
importjavax.xml.parsers.SAXParserFactory;
importjavax.xml.parsers.FactoryConfigurationError;
importjavax.xml.parsers.ParserConfigurationException;
importjavax.xml.parsers.SAXParser;
importjava.io.IOException;
importjavax.servlet.jsp.tagext.PageData;
publicclassValidateHandlerextendsDefaultHandler{
privateStringfileName="";
publicvoidstartElement(StringnameSpaceuri,
Stringsname,Stringqname,Attributesattrs){
for(inti=0;i<attrs.getLength();i++)
if("filename".equals(attrs.getLocalName(i)))
this.fileName=attrs.getValue(i);
}
publicStringgetFilename(PageDatapage)
throwsFactoryConfigurationError,ParserConfigurationException,
SAXException,IOException{
try{
SAXParserFactoryfactory=SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
SAXParsersaxparser=factory.newSAXParser();
saxparser.parse(page.getInputStream(),this);
}catch(FactoryConfigurationErrorfe){
throwfe;
}catch(ParserConfigurationExceptionpce){
throwpce;
}catch(SAXExceptionse){
throwse;
}catch(java.io.IOExceptionio){
throwio;
}finally{
returnthis.fileName;}
}
publicvoiderror(SAXParseExceptione)
throwsSAXParseException
{
throwe;
}
}
Example5-17showstheXMLviewgeneratedfromtheJSPpageofExample5-13(withsomecarriagereturnsadded).Itmightbeugly,butnowyouknowwhatanXMLviewlookslike!TheHTMLcodeisalltreatedastemplatedata,enclosedinajsp:textelementandCDATAsections.ThetwoXMLelements,jsp:rootandt:toxml,aregivensequentialIDnumbersaspartoftheirjsp:idattributesintheXMLview.TheTagLibraryValidatorclasscanusetheseIDstoprovidefinelygrainedXML-relatedmessagesinvolvingthevalidatedJSPpage.
Example5-17.TheXMLviewofExample5-13
<jsp:rootjsp:id="0"xmlns:jsp="http://java.sun.com/JSP/Page"version="1.2"
xmlns:t="/toxml_view">
<jsp:text><![CDATA[]]></jsp:text>
<jsp:text><![CDATA[<html>]]></jsp:text>
<jsp:text><![CDATA[<head>]]></jsp:text>
<jsp:text><![CDATA[<title>Testtld]]></jsp:text>
<jsp:text><![CDATA[</title>]]></jsp:text>
<jsp:text><![CDATA[</head>]]></jsp:text>
<jsp:text><![CDATA[<bodybgcolor="#ffffff">Hello,thispageisusingthetoxmltagto
lookatitsXMLView.]]></jsp:text>
<t:toxmljsp:id="1"filename="my_xmlview"/>
<jsp:text><![CDATA[]]></jsp:text>
<jsp:text><![CDATA[</body>]]></jsp:text>
<jsp:text><![CDATA[</html>]]></jsp:text>
</jsp:root>
SeeAlso
Recipe5.5oncreatingaJSPfromscratchasaJSPdocument;ChapterJSP.6(JSPdocuments)oftheJSP2.0specification;ChapterJSP.10(XMLviews)oftheJSP2.0specification.
Chapter6.DynamicallyIncludingContentinServletsandJSPs
Introduction
Recipe6.1.IncludingaResourceEachTimeaServletHandlesaRequest
Recipe6.2.UsinganExternalConfigurationtoIncludeaResourceinaServlet
Recipe6.3.IncludingResourcesNestedatMultipleLevelsinaServlet
Recipe6.4.IncludingaResourcethatSeldomChangesintoaJSP
Recipe6.5.IncludingContentinaJSPEachTimetheJSPHandlesaRequest
Recipe6.6.UsinganExternalConfigurationFiletoIncludeaResourceinaJSP
Recipe6.7.IncludinganXMLFragmentinaJSPDocument
Recipe6.8.IncludingContentfromOutsideaContextinaJSP
Introduction
ServletsandJSPsoftenincludefragmentsofinformationthatarecommontoanorganization,suchaslogos,copyrights,trademarks,ornavigationbars.Thewebapplicationusestheincludemechanismstoimporttheinformationwhereveritisneeded,sinceitiseasiertochangecontentinoneplacethentomaintainitineverypieceofcodewhereitisused.Someofthisinformationisstaticandeitherneverorrarelychanges,suchasanorganization'slogo.Inothercases,theinformationismoredynamicandchangesoftenandunpredictably,suchasatextualgreetingthatmustbelocalizedforeachuser.Inbothcases,youwanttoensurethattheservletorJSPcanevolveindependentlyofitsincludedcontent,andthattheimplementationoftheservletorJSPproperlyupdatesitsincludedcontentasnecessary.
ThischapterrecommendsrecipesforincludingcontentinbothservletsandJSPsunderseveralconditions:
Whentheincludedinformationisrefreshedeverytimeausermakesarequest.
Whentheincludedinformationinvolvestwoormorenestedlevelsforexample,whenanincludedfileinturnincludesanotherpieceofinformation,andsoon.
Whenyouwanttousethedeploymentdescriptortoupdatetheitemthataservletincludes,whichisahandy,lesserror-pronewayofincludingcontentwhenthecontentisconfigurableandchangesratheroften.
WhenyouwanttoimportresourcesintoaJSPfromoutsidethewebapplication.
Recipe6.1describeshowtoimportaresourceeachtimetheservlet
handlesarequest.
Recipe6.1IncludingaResourceEachTimeaServletHandlesaRequest
Problem
Youwanttoincludeinformationfromanexternalfileinaservleteachtimetheservlethandlesarequest.
Solution
Usethejavax.servlet.RequestDispatcher.include(request,response)
methodinthedoGet()methodoftheservletthatincludestheexternalfile.
Discussion
Includingthecontentinthejavax.servlet.http.HttpServlet'sdoGet()methodinitiatestheincludemechanismwheneverthewebcontainerreceivesaGETrequestfortheservlet.
Whenusingthisdesign,implementtheservlet'sdoPost()methodtocalldoGet(request,response).
Example6-1showsaservletthatimportsacopyrighttemplateinthedoGet()methodusingthe
javax.servlet.RequestDispatcher.include()method.
Example6-1.IncludingcontentintheHttpServlet'sinit()method
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassIncludeServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>IncludeServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>WelcomeToOurUniverse</h1>");
out.println("Imaginetherestofthepagehere.<br><br>");
//Includethecopyrightinformation
RequestDispatcherdispatcher=request.getRequestDispatcher(
"/copyright");
dispatcher.include(request,response);
out.println("</body>");
out.println("</html>");
}//doGet
}
Example6-1getsaRequestDispatcherobjectbycallingthejavax.servlet.ServletRequest.getRequestDispatcher()
method.TheparametertothegetRequestDispatcher()methodinthiscaseistheservletpathtotheresourcethattheincludeservletimports:/copyright.Thispathismappedinweb.xmltotheCopyrightservlet,whichisshowninExample6-2.
Example6-2.TheimportedCopyrightservlet
publicclassCopyrightextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
java.io.PrintWriterout=response.getWriter();
out.println("Copyright©2003-2004EmbraceAndExtendCorp.");
}
}
TheCopyrightservletoutputsalineoftextthatincludesthecharacterentitycodeforthecopyrightsymbol(©),sothatthecopyrightsymbolisdisplayedcorrectlyintheresultingHTML.Whentheimportingservletcallstheinclude()method,thecopyrighttextisinsertedinthemethodcall'scodelocation.
AservletcanimportanHTMLpage,aswellastheoutputofaJSPpageorservlet.IfyouareimportingHTMLfragmentsinthismanner,makesurethattheimportedtextdoesnotbreakyourHTMLpage,suchasbyrepeatingHTMLtagsorfailingtoclosecertaintags.
Figure6-1showsthepagegeneratedbytheIncludeServletina
browser.
Figure6-1.TheIncludeServlet'spageinabrowser
Recipe6.2describeshowtoconfiguretheimportedresourceinanexternalconfigurationfile,suchasweb.xml.
JasonHunter,whoprovidedatechnicalreviewofthisbook,pointsoutthatmanypeopleareusinganofflinebuildprocesstopregeneratestatic(e.g.,HTML)fileswhenalotofthesite'swebcontentusesincludes,suchasimportingheadersandfootersintomostofthewebsite'spages.Inmostcases,theservercanhandletherequestsforstaticfilesmuchmoreefficientlythanrequestsfordynamicpages(suchasaJSPthatincludesotherresources).SeeChapter3,ServletBestPractices,inthebookJavaEnterpriseBestPractices(O'Reilly).
SeeAlso
Recipe6.2andRecipe6.3onincludingresourcesinservlets;Recipe6.4-Recipe6.7onusingjsp:include,theincludedirective,aswellasincludingresourcesintoJSPdocumentsorXMLfiles;ChapterSRV.14.2.5oftheServlet2.4specification;ChapterJSP.5.4onoftheJSP2.0specificationonjsp:include;ChapterJSP.1.10.3oftheJSP
2.0specificationontheincludedirective.
Recipe6.2UsinganExternalConfigurationtoIncludeaResourceinaServlet
Problem
Youwanttouseanexternalconfigurationfile(suchasweb.xml)toconfiguretheresourcethatisincludedinaservlet.
Solution
Useinitparameterswiththeincludingservlettoallowtheexternalconfigurationoftheincludemechanism,thenincludetheresourcewiththejavax.servlet.RequestDispatcher.include(request,response)
method.
Discussion
Youmaywanttoperiodicallychangetheresourcethataservletincludes,withoutchangingandrecompilingtheservletcode.Youcanmakethesechangesbyalteringtheservlet'sinitparametersinweb.xml.Usingthisstrategy,eithertheincludedresource'sfilelocationitselforthemethodofretrievingtheresource(suchasfromadatabase)canchange.Youcanensurethattheservletimportsthecorrectresourcebyalteringthecontentoftheparam-valueelement.Example6-3showsaservletthatisconfiguredtoincludeafilenamedprivacy.jspf.Thisrepresentsastandardprivacystatementforthewebapplication.
Example6-3.Specifyinganincludedresourcebyusingtheservlet'sinit-paramelement
<servlet>
<servlet-name>PrivacyServlet</servlet-name>
<servlet-class>com.jspservletcookbook.IncludeServlet</servlet-class>
<init-param>
<param-name>included-resource</param-name>
<param-value>privacy.jspf</param-value>
<init-param>
</servlet>
Example6-4showsthedoGet()methodofthePrivacyServlet.Thismethodgetsthevalueoftheincluded-resourceinitparameter(privacy.jspf),thenincludestheJSPsegment.
Example6-4.Includingaresourcespecifiedbyaninitparameter
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>IncludeServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>WelcomeToOurUniverse</h1>");
out.println("Imaginetherestofthepagehere.<br><br>");
//Includetheprivacyinformationbasedonaninit-paramvalue
StringincludeRes=(String)getInitParameter(
"included-resource");
//getaRequestDispatcherobjectbasedontheinit-paramvalue
RequestDispatcherdispatcher=request.
getRequestDispatcher(includeRes);
dispatcher.include(request,response);
out.println("</body>");
out.println("</html>");
}
Example6-4getsaRequestDispatcherrepresentingtheconfiguredinit-paramvaluewiththiscode:
//theincludeResvariableholdstheinit-paramvalue"privacy.jspf"
RequestDispatcherdispatcher=request.getRequestDispatcher(includeRes);
Thenthedispatcher.include(request,response)methodisreplacedbytheoutputoftheprivacy.jspffile.Example6-5showstheJSPsegmentthatthePrivacyServletincludes.TheJSP'scontenthassomeHTMLtagsthatfitintotheHTMLrepresentedbytheincludingpage.
Example6-5.AJSPsegmentincludedinaservletwithaRequestDispatcher
<%@pageerrorPage="/error.jsp"%>
<p><strong>ParkerRiverNetSolutionsPrivacyPolicy</strong></p>
<p>AnypersonalinformationyouprovidetousregardingWeb-orsoftware-development
servicesorsharewaresoftware,suchasyourname,address,telephonenumber,ande-mail
address,willnotbereleased,sold,orrentedtoanyentitiesorindividualsoutside
ofParkerRiverNetSolutions.</p>
Includedsegmentsorpagescannotsetorchangeresponseheaders,soanyattemptstosetthecontenttypeinanincludedservletorJSPasin:
<%@pagecontentType="text/xml"%>
areignored.
AlltheincludedJSPdoesisspecifyanerrorpagecomposedofsomeformatting-relatedHTMLtagsandtext.Figure6-2showsthebrowserpageforthePrivacyServlet.
Figure6-2.AwebpagewithanincludedJSPsegment
YoumayalsowanttoaugmentExample6-4toprovideadefaultresourceforinclusionintheservlet,justincasethedeploymentdescriptor(web.xml)mistakenlyomitsaninitparameterfortheservlet.ThemethodgetInitParameterreturnsnullintheeventofthisomission.Youcouldtestforthisnullconditionandthenprovideadefaultvaluefortheincludedstatement.
SeeAlso
Recipe6.3onincludingresourcesthathavenestedincludes;Recipe6.4-Recipe6.8onincludingresourcesinJSPs;ChapterSRV.14.2.5oftheServletRecipe2.4specification;ChapterJSP.1.10.3oftheJSP2.0specificationonincludingfilesinJSPs.
Recipe6.3IncludingResourcesNestedatMultipleLevelsinaServlet
Problem
Youwanttoincluderesourcesinaservletthatalreadyincludeservlets,JSPs,orHTML.
Solution
Usethejavax.servlet.RequestDispatcher.include(request,response)
methodtoincludethetop-levelfile.Makesurethaterrorpagesareproperlyconfiguredinweb.xml,justincaseanexceptionisthrowninadeep-nested,importedfile.
Discussion
Eventhoughitdoesnotrepresentthebestarchitecturaldecision,itispossibleforaservlettoincludearesourcethatitselfincludesanotherresource,resultinginanumberofinclusionstakingplacebeneaththesurface.ImaginetheRussiandollsthatfitinsideeachother.Youunscrewthetophalfofthedolls,onlytofindsmallerreplicasofthedollsnestedinsidetheouterones.ItisnotoutlandishtothinkofverycomplexwebpagesusingHTMLframeandtabletags,containingheadersandfooters,withthesesegmentsofthepagecontainingotherspecializedcontentusinganincludemechanism.Oneoftheincludedfilesnestedseverallevelsdeepcouldthrowanexceptionorcorruptthechainofinclusionsinsomemanner.Althoughthereisnofoolproofwaytodefendagainstthisoccurrence,forthepurposesofdebugging,makesurethatthewebapplicationhasanerrorpageconfiguredsothatitcandisplayinformation
abouttheresourcethatranintoincludeproblems.
Thisrecipeprovidesanexampleofaservletthathasthreelevelsofincludedresources.TheouterservletincludesanotherservletnamedLevel2,whichincludesaJSPlevel3.jsp,whichcompletesthepicturebyincludingtheinnerservlet,Level4.Figure6-3showsthebrowserdisplaywhenauserrequeststhecom.jspservletcookbook.MultipleIncservlet.
Figure6-3.Threeincludedfilesinonewebpage
Example6-6showstheservletcode.Thisservletisresponsibleforthefirstleveloftext("HellofromLevel1"),theneachoftheincludedresourcescontributescontenttotheresponse.
Example6-6.Theouterincludedservlet
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassMultipleIncextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>MultipleIncludes</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>HellofromLevel1</h1>");
out.println("ThistextisdisplayedatLevel1.");
RequestDispatcherdispatcher=request.
getRequestDispatcher("/level2");
dispatcher.include(request,response);
out.println("</body>");
out.println("</html>");
}
}
Thecode:
RequestDispatcherdispatcher=request.getRequestDispatcher("/level2");
dispatcher.include(request,response);
includestheoutputoftheservletthatismappedtotheservletpath/level2,whichExample6-7shows(justthedoGetmethod).
Example6-7.Thefirstinnerincludedservlet
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throws
ServletException,IOException{
java.io.PrintWriterout=response.getWriter();
out.println("<h2>HellofromLevel2</h2>");
out.println("ThistextisincludedatLevel2.");
//IncludetheJSPfilenamed"level3.jsp"
try{
RequestDispatcherdispatcher=request.getRequestDispatcher(
"/level3.jsp");
dispatcher.include(request,response);
}catch(Exceptionse){
Stringcontext_path=(String)request.getAttribute(
"javax.servlet.include.context_path");
Stringservlet_path=(String)request.getAttribute(
"javax.servlet.include.servlet_path");
StringerrMessage=newStringBuffer(
"ExceptionraisedduringLevel2servletinclude:<br>").
append("Contextpath:"+context_path+"<br>").
append("Servletpath:"+servlet_path).toString();
thrownewServletException(errMessage);
}
}
Example6-7writesmoretexttotheresponse,thenincludesalevel3.jsp,liketheouterservlet,usingajavax.servlet.RequestDispatcherobjecttoinitiateincludingtheJSP.TheLevel2servletdoessomeotherstuffwithatry/catchblockandrequestattributes,inordertodemonstratethehandlingofexceptionsthatmaybethrownduringincludeoperations.
AccordingtotheJSPAPIspecification,includedresourceshaveaccesstofiverequestattributes:
javax.servlet.include.request_uri
javax.servlet.include.context_path
javax.servlet.include.servlet_path
javax.servlet.include.path_info
javax.servlet.include.query_string
Inthecatchblock,theLevel2servletgetsthevalueoftwooftheserequestattributeswith:
Stringcontext_path=
(String)request.getAttribute("javax.servlet.include.context_path");
Stringservlet_path=
(String)request.getAttribute("javax.servlet.include.servlet_path");
Inthecatchblock,theLevel2servletthenthrowsanewServletExceptionwiththeattributevaluesaspartoftheexceptionmessage.Anerrorpageconfiguredforthewebapplicationdisplaysinformationabouttheexceptionthatwasgeneratedbytheincludeoperation.
Theerror-pageconfigurationinweb.xmllookslike:
<error-page>
<exception-type>
javax.servlet.ServletException
</exception-type>
<location>/error</location>
</error-page>
where"/error"ismappedtoaservletthatdisplaysexception-relatedinformation.
InExample6-7,thecontextpathwasemptyandtheservletpathwas
/level2.Figure6-4showsabrowserdisplayingtheerrorpage.Theservletgeneratingtheexceptionisspecifiedasthetop-levelservlet(MultipleInc)becausethiswasthecodethatoriginatedtheincludemechanismwhichresultedintheServletException.
Figure6-4.Displayingexceptioninformationcausedduringanincludeoperation
Example6-8showstheJSPfile(level3.jsp)thatthefirstinnerservletimports.Thelevel3.jspfilerepresentsthesecondlevelofincludedcontent.
Theincludedservletsdonotcallthejava.io.PrintWriter.close()method,becausethatactionwouldpreventtheresponsethatfollowstheouterservlet'sincludecodefrombeingsenttotheclient.Theouterservlet(MultipleIncinExample6-6)finallycallsPrintWriter.close()whenitisfinishedincludingthenestedresources.
Example6-8.Theincludedlevel3.jspJSPfile
<%@pageerrorPage="/error"%>
<h3>HellofromLevel3</h3>
ThistextisincludedatLevel3.
<jsp:includepage="/level4"/>
Finally,theJSPfileusesthejsp:includestandardactiontoimportthetextreturnedfromaservletthatismappedtothe/level4path.TheLevel4servletdoesthesamethingastheotheroftherecipe'sservletsitwritescharacterdatatothePrintWriterobjectsoIhavenotshownitssourcecode.ThereasonIincludedwastodemonstratehowseveraldifferentresourcetypescanbenestedinachainofincludedfiles.Theouterservletincludesservlettwo,whichincludesaJSPfile,whichinturnincludesthetextreturnedfromathirdservlet.ThefirstincludedservletencloseditsownincludecodeinatryblocktocatchanyexceptionsraisedbyincludingaJSPfile.
SeeAlso
Recipe6.1onusingtheRequestDispatcherincludemechanism;Recipe6.2ondetermininganincludedresourcewithanconfigurationfile;Recipe6.4-Recipe6.8onincludingresourcesinJSPs;ChapterSRV.14.2.5oftheServletRecipe2.4proposedfinalspecification;ChapterJSP.1.10.3oftheJSP2.0specificationonincludingfilesinJSPs;Chapter9onspecifyingerrorspagesinwebapplications.
Recipe6.4IncludingaResourcethatSeldomChangesintoaJSP
Problem
Youwanttoincludearesourcethatdoesnotchangeverymuch(suchasapagefragmentthatrepresentsaheaderorfooter)inaJSP.
Solution
UsetheincludedirectiveintheincludingJSPpage,andgivetheincludedJSPsegmenta.jspfextension.
Discussion
JSPpagesareoftencompositesofpagefragmentsthatrepresentnavigationbars,headers(pageelementsthatappearatthetopofawebpage),footers(elementsthatappearatthebottomofawebpage),andthemainbodycontent.Sincepagesinawebapplicationorasitemayallusethesamenavigationbar,thisfileismaintainedinoneplaceandusedbyallofthewebcomponentsthatrequireit.IfyouaregoingtoimportaJSPsegmentthatisastaticorunchangingresource,usetheincludedirectiveintheJSP,asin:
<%@includefile="/WEB-INF/jspf/navbar.jspf"%>
IfyouareusingaJSPdocument(seeChapter5)orXMLsyntaxfortheJSP,usethisformoftheincludedirective:
<jsp:directive.includefile="/WEB-INF/jspf/navbar.jspf"/>
Ifthevalueofthefileattributebeginswitha"/"character,thenitisacontext-relativepath,meaningthatitisrelativetothewebapplicationcontainingtheJSPthatusesthisdirective.IftheJSPincludesthelatterdirective,thenthisfilepathmeans"beginatthewebapplicationrootandincludethe/WEB-INF/jspf/navbar.jspffile."
Afileattributevalueinincludethatdoesnotbeginwitha"/"characterisapage-relativepath,whichisrelativetotheJSPpagethatisusingtheincludedirective.Thefollowingincludedirectiveattemptstoincludeafileinsideofthesegmentsdirectory,whichhasthesameparentdirectoryastheincludingJSP:
<%@includefile="segments/navbar.jspf"%>
Theincludedirectiveincludesthetextorcodeoftheincludedsegmentduringthetranslationphase,whentheJSPisconvertedintoaservlet.TheincludemechanismisamoreefficientwayofimportingthetextorcodethatyouwouldotherwisetypeintoaJSPpriortoitsconversiontoaservlet,suchasHTMLtagsortaglibdirectives.Example6-9showshowtousetheincludedirectivetoimportasegmentoftaglibdirectivesintoaJSP.
Thedifferencebetweentheincludedirectiveandthejsp:includestandardactionisthattheincludedirectiveimportstheactualtextorbytesoftheincludedsegment,whereasthejsp:includestandardactionsendsarequesttotheincludedpageandthenincludesthedynamicresponsetothatrequest.SeeRecipe6.5.
Example6-9.IncludingaJSPsegmentintoaJSPpageattranslationtime
<%@pagecontentType="text/html"%>
<%@includefile="/WEB-INF/jspf/taglib-inc.jspf"%>
<html>
<head>
<title>MainContent</title>
</head>
<body>
<h1>Hereisthemaincontent</h1>
ThiswebapplicationisusingthefollowingServletAPI:
<c:outvalue="${pageContext.servletContext.majorVersion}"/>.<c:outvalue=
"${pageContext.servletContext.minorVersion}"/><br><br>
<jsp:useBeanid="timeValues"class="java.util.Date"/>
<c:settarget="${timeValues}"value=
"${pageContext.session.creationTime}"property="time"/>
Thesessioncreationtime:
<fmt:formatDatevalue="${timeValues}"type="both"dateStyle=
"medium"/><br><br>
ThetoXmltagwillcreateanXMLviewofthispage.
<t:toXmlfilename="include-xmlview"/>
</body>
</html>
ThesecondlineofExample6-9includesaJSPsegmentnamedtaglib-inc.jspf.ThissegmentincludesthetaglibdirectivesresponsibleformakingavailabletheJSTLandcustomtagusedinthepage.Example6-10showsthetaglib-inc.jspfpage.
Example6-10.AJSPsegmentcontainingtaglibdirectives
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%@tagliburi="http://java.sun.com/jstl/fmt"prefix="fmt"%>
<%@tagliburi="/toxml_view"prefix="t"%>
Theincludedirectiveincludesthesethreetaglibdirectivesjustasifyouhadtypedtheminyourself,thentheJSPcontainerconvertsthe
enclosingJSPintoaservlet.ThethreetaglibdirectivesenabletheuseofthefollowingtagsinExample6-9:
c:out
c:set
fmt:formatDate
t:toXml
TheJSP2.0specificationrecommendsthatyougiveincompleteJSPcodethatisdesignedtobeincludedinotherfilesa.jspfextension,whichusedtomean"JSPfragment."The2.0specification,however,nowreferstothesefragmentsas"JSPsegments"inordertoavoidconfusingthesefileswiththejavax.servlet.jsp.tagext.JspFragmentinterface.ThisinterfaceispartofthetagextensionAPI.
Figure6-5showswhattheJSPlookslikeinabrowserwindow.
Figure6-5.AJSPwithanincludedJSPsegmentoftaglibdirectives
ThispagedisplaystheServletAPIusedbythewebcontainer,thejavax.servlet.http.HttpSessioncreationtime(formattedusingthefmt:formatDateJSTLtag),andthecustomtagthatisdescribedinRecipe5.6.ThistaggeneratesanXMLviewofthecontainingpageandsavesanewXMLfilenamedaccordingtoitsfilenameattribute.Itwasincludedtoshowamethodofincludingafewdifferenttypesoftaglibs.
SeeAlso
Recipe6.5onusingthejsp:includestandardaction;Recipe6.7onincludingJSPsegmentsinXMLfiles;Recipe6.8onincludingcontentfromoutsideofaJSP'scontext;ChapterJSP.1.10.3oftheJSP2.0specificationonincludingfilesinJSPs;Chapter23ontheJSTLtags.
Recipe6.5IncludingContentinaJSPEachTimetheJSPHandlesaRequest
Problem
YouwanttoincludecontentinaJSPeachtimeitreceivesarequest,ratherthanwhentheJSPisconvertedtoaservlet.
Solution
Usethejsp:includestandardaction.
Discussion
Thejsp:includeactionincludesaresourceinaJSPeachtimeitreceivesarequest,whichmakesjsp:includemoreofadynamicincludemechanismthantheincludedirective(seeRecipe6.4).Usingjsp:include,theincludedJSPsegmentshaveaccesstotheincludingpage'srequest,session,andapplicationimplicitobjects,andtoanyattributestheseobjectscontain.Usethejsp:includeactionineachlocationofthefilewhereyouneedtoimportresourcessuchasJSPsegmentsfromthesamewebapplication.
Theimportcustomaction,whichispartofthecoreJSTL,canimportresourcesfromotherwebapplicationsorfromotherlocationsontheInternet.SeeRecipe6.8.
Example6-10showsaJSPpagethatreceivessubmittedforminformationfromanotherpageinthewebapplication.Thereceivingpageusesjsp:includetoincludeheaderandfooterpagesegmentsatthetopandbottomofthepage.
Justtoshowthattheincludedsegmentshaveaccesstothesamerequestandsessioninformationastheirparentpage,theheadersegmentdisplaystheperson'ssubmittedname,whichisstoredinfnameandlnamerequestparameters,intheformofagreeting-relatedtitleHTMLtag.ThefooterpageelementdisplaysthesessionIDalongwiththeuser'ssubmittedfirstandlastname.First,Figure6-6showsanHTMLpagewithasimplesubmissionformfortheuser'sfirstname,lastname,andemailaddress.
Figure6-6.AnHTMLform
AssumethatthisformpageincludesembeddedJavaScripttocheckthevalidityoftheenteredinformation.WhentheuserclickstheSubmitbutton,theforminformationissubmittedwiththefollowingHTMLtagto/solutions.jsp:
<formmethod=postaction="/solutions.jsp">
Example6-11showsthesolutions.jsppage,whichincludestwoJSPsegments:header.jspfandfooter.jspf.Theheader.jspfcontainsthecontentsofaheadHTMLtag,andplacestheuser'ssubmittednameinitsnestedtitletag.Thefooter.jspfpageforthesakeofdemonstrationechoestheuser'snameandshowshissessionID,whichitobtainsfromtheimplicitsessionJSPobject.TheJSP2.0specificationrecommendsthatyoukeepthesefilesinWEB-INF/jspf.
Example6-11.Includingtwopagesegmentsanddisplayingsubmittedformvalues
<%@pagecontentType="text/html"%>
<html>
<jsp:includepage="/WEB-INF/jspf/header.jspf"/>
<bodybgcolor="white">
<tablewidth="660"border="0"summary="Atwo-columntableinwhichresidesalogoand
navigationbar">
<tr><tdvalign="top">
Organizationimagegoeshere...<p>
<u>Main</u>
</td>
<tdalign="right"valign="top">
Navbargoeshere...
</td></tr><tr><tdvalign="top"align="center"colspan="2">
<tableborder="0"summary=
"Anestedtableforaligningbodycontent">
<tr><td><h2>Thanksforregisteringatthissite</h2></td></tr>
<tr><td>Hereistheinfoyousubmitted:</td></tr>
<tr><td>Name:
<%=request.getParameter("fname")%>
<%=request.getParameter("lname")%></td></tr>
<tr><td>Email:
<%=request.getParameter("eaddress")%>
</td></tr></table>
</td></tr><tr><td></td></tr>
</table>
<tablewidth="660"border="0"summary=
"Atablecontainingafooternavigationbar.">
<tr><tdvalign="top"align="center">
<jsp:includepage="/WEB-INF/jspf/footer.jsp"/>
</td></tr>
</table>
</body>
</html>
Example6-12showstheheader.jspfJSPsegment.
Example6-12.AJSPheadersegmentincludedwithjsp:include
<HEAD>
<METAname="author"content=
"BruceW.Perry,[email protected]">
<METAname="keywords"content=
"Java,JSP,servlets,databases,MySQL,Oracle,webdevelopment">
<TITLE>ParkerRiver:ThanksForVisiting
<%=request.getParameter("fname")%>
<%=request.getParameter("lname")%>
</TITLE>
</HEAD>
Allthissegmentdoesisincludetheuser'snameinthetitletag.Example6-13showstheimportedfooter.jspfsegment.Thissegmentalsowritestheuser'snametothedisplayedoutputandaddsthesessionID,aftercheckingwhetherthejavax.servlet.http.HttpSessionobjectisnull,andbeforeitcallstheHttpSession.getId()method.
Example6-13.AJSPfootersegmentincludedwithjsp:include
Thanksforvisiting
<%=request.getParameter("fname")%>
<%=request.getParameter("lname")%><br>
SessionID:
<%if(request.getSession()!=null){%>
<%=request.getSession().getId()%>
<%}else{%>
Unknown
<%}%><br><br>
<ahref="/index.html">Main</a>|<ahref="/service.html">Services</a>|
<ahref="/sitemap.html">SiteMap</a>|
<ahref="/resources.html">Resources</a>|
<ahref="/contacts.html">ContactUs</a>|
<ahref="/prns_privacy.html">Privacy</a>
Figure6-7showsthesolutions.jsppageinawebbrowser.
Figure6-7.Theincludedheaderandfootersegmentsdisplayedinawebbrowser
Usingjsp:include,changestoincludedfilesarereflectedimmediatelyintheincludingpages.Ontheotherhand,ifyoumakechangestoapagethatisincludedusingtheincludedirective,thosechangesarenotreflectedintheincludingpageuntilyoumodifythatpageandforcetheJSPcontainertorecompileit.
SeeAlso
Recipe6.4ontheincludedirective;Recipe6.7onincludingJSPsegmentsinXMLfiles;Recipe6.8onincludingcontentfromoutsideofaJSP'scontext;ChapterJSP.1.10.3oftheJSP2.0specificationonincludingfilesinJSPs;Chapter23ontheJSTLtags.
Recipe6.6UsinganExternalConfigurationFiletoIncludeaResourceinaJSP
Problem
YouwanttoincludeafiledynamicallyinaJSP,basedonavaluederivedfromaconfigurationfile.
Solution
Usethejsp:includestandardaction.Providethevalueinanexternalpropertiesfileorasaconfigurationparameterinthedeploymentdescriptor.
Discussion
UsinganexternalconfigurationtospecifyanincludefileforaJSPallowsyoutochangethenameand/orpathtotheincludedfilewithouttouchingtheJSP'scode.Inaddition,whenusingjsp:includetheJSPdoesnothavetoberecompiledtoreflectanychangesintheincludedfilethewebresourceisincludedbytheJSPeachtimeithandlesarequest.Ifyouchangethefilepointedtobytheconfigurationfile,theresponsefromtheincludedresourceisaddedtotheincludingJSP'sresponseduringthenextrequest.
Thedifferencebetweenajsp:includestandardactionandincludedirectiveisthattheincludedirectiveincludesthebytesorcontentsoftheimportedfilebeforetheJSPiscompiled(duringthetranslationphasefortheJSP).Iftheincludedsegmentchanges,theupdateswillnotbereflectedintheJSPuntiltheJSPitselfismodified,whichcausesaJSPcontainer(suchasTomcat'sJasperJSPcontainer)torecompiletheJSP.
Example6-14showsaJSPthatusesanexternalpropertiesfiletospecifythefiletoinclude.
Example6-14.Usingjava.util.ResourceBundle.getBundle()tofetchanexternallyconfiguredfile
<%@pagecontentType="text/html"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<%java.util.ResourceBundlebundle=
java.util.ResourceBundle.getBundle("com.jspservletcookbook.include");
Stringsegment=bundle.getString("external-include");%>
<jsp:includepage="<%=segment%>"/>
<body>
<h2>WelcometoourPortalHome<c:outvalue="${param.fname}"/><c:outvalue="${param.
lname}"/></h2>
<jsp:useBeanid="dateString"class="java.util.Date"/>
Thetimeis<c:outvalue="${dateString}"/>.<br><br>
</body>
</html>
Example6-14includesaJSPsegmentthatisfoundatthepathspecifiedbytheexternal-includeproperty.Thispropertyiswritteninasimpletextfilecalledinclude.properties,withcontentthatlookslikethis:
external-include=WEB-INF/jspf/header_tag.jsp
Theinclude.propertiesfileisstoredinWEB-INF/classes/com/jspservletcookbook.Whenyour
servletorJSPattemptstoaccessalistofpropertyvaluesbycallingthestaticmethodjava.util.ReseourceBundle.getBundle("com.jspservletcookbook.include"),getBundleautomaticallyreplacestheperiod"."characterswith"/"andappends".properties"totheendoftheString(makingthesearchlooklike"com/jspservletcookbook/include.properties"inourexample).
TheexamplecodesavesthepropertyvalueinaStringvariablesegmentwiththefollowingcode:
Stringsegment=bundle.getString("external-include");
Thenthevalueofthesegmentvariable,whichisafilepath,specifiesthefilefortheJSPtoinclude:WEB-INF/jspf/header_tag.jsp.ThisisaccomplishedwiththeJSPexpression<%=segment%>inthepageattributevalueforjsp:include:
<jsp:includepage="<%=segment%>"/>
WhentheJSPpageisexecuted,theincludedfile'sresponseisincludedinthepartofthepagewherethejsp:includestandardactionoccurs.Example6-15showsthecontentoftheincludedfile,header_tag.jsp.
Example6-15.Thecontentoftheheader_tag.jspsegment
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<HEAD>
<METAname="author"content=
"BruceW.Perry,[email protected]">
<METAname="keywords"content=
"Java,JSP,servlets,databases,MySQL,Oracle,webdevelopment">
<TITLE>ParkerRiver:ThanksForVisiting
<c:outvalue="${param.fname}"/>
<c:outvalue="${param.lname}"/>
</TITLE>
</HEAD>
ThisisacompleteHEADHTMLtag,includingtwonestedMETAtagsandaTITLEtag.IfyourequestedtheincludingJSPpageathttp://localhost:8080/home/externalInclude.jsp?fname=Mister&lname=Bean,thereturnedcontentfromthisJSPsegmenttheactualtextthattheJSPcontainersubstitutesforthejsp:includetagintheoutputlookslikeExample6-16.
Example6-16.Theoutputwhenjsp:includeisused
<HEAD>
<METAname="author"content=
"BruceW.Perry,[email protected]">
<METAname="keywords"content=
"Java,JSP,servlets,databases,MySQL,Oracle,webdevelopment">
<TITLE>ParkerRiver:ThanksForVisiting
Mister
Bean
</TITLE>
</HEAD>
Theincludedsegmentprocessestherequestparametersfnameandlnamefromthequerystring:
fname=Mister&lname=Bean
andincludestheirvaluesintheTITLEtag.Figure6-8showswhattheexternalInclude.jsppagelookslikeinabrowser.
Figure6-8.BrowserviewofJSPthatusesjsp:includetoincludeanotherJSPsegment
Inthisexample,theincludedsegmentusesthepropertaglibdirectivesothatthec:outJSTL1.0tagscanbeused.IfyouareusingJSTL1.1,thentheuriattributevalueishttp://java.sun.com/jsp/jstl/core:
<%@taglib
uri="http://java.sun.com/jstl/core"
prefix="c"%>
Youcanalsopassparametersfortheincludedsegmenttoprocess,inthemannerof:
<jsp:includepage="<%=segment%>">
<jsp:paramname="role"value="comedian"/>
</jsp:include>
Ifyouwanttouseacontextparameterinthewebapplication'sdeploymentdescriptorinsteadtoprovideapathfortheincludedfile,addacontext-paramelementtoweb.xml(asshowninExample6-17).
Example6-17.Acontext-paramelementprovidesanincludedfilepath
<context-param>
<param-name>external-include</param-name>
<param-value>WEB-INF/jspf/header_tag.jsp</param-value>
</context-param>
ThengetthevalueofthecontextparameterintheincludingJSP:
<jsp:includepage="<%=application.getInitParameter("external-include")%>"/>
TheJSPtheninsertsthefilepathWEB-INF/jspf/header_tag.jspasthevalueforthejsp:includepageattribute.
SeeAlso
Recipe6.4ontheincludedirective;Recipe6.7onincludingJSPsegmentsinXMLfiles;Recipe6.8onincludingcontentfromoutsideofaJSP'scontext;ChapterJSP.1.10.3oftheJSP2.0specificationonincludingfilesinJSPs;Chapter23ontheJSTLtags;thiswebpageforhowthegetBundlemethodreturnscertaintypesofResourceBundles:http://java.sun.com/j2se/1.4.1/docs/api/java/util/ResourceBundle.html#getBundlejava.util.Locale,java.lang.ClassLoader).
Recipe6.7IncludinganXMLFragmentinaJSPDocument
Problem
YouwanttoincludeafragmentofanXMLfileinsideofaJSPdocument,orincludeaJSPpageinXMLsyntax.
Solution
Usethejsp:includestandardactionfortheincludesthatyouwanttooccurwitheachrequestoftheJSP.Usethejsp:directive.includeelementiftheincludeactionshouldoccurduringthetranslationphase.
Discussion
BecauseaJSPdocumentisawell-formedXMLfile,bothofthemechanismsthatyoucanusetoincludeJSPsegmentsareXMLelements:jsp:includeandjsp:directive.include.AJSPdocumentisaJSPpageinXMLsyntax,inwhichallofthecodeiswell-formedXML;inotherwords,theentirepageconsistsofXMLelements,attributes,andthebodycontentofsomeXMLelements.YouthentaketheJSPdocumentandplaceitintherootofyourwebapplication(orwhereveryoumakeyourJSPpagesavailable;therootistheusualplace),andtheJSPcontainertranslatestheXMLfileintoaservlet.OnereasonforusingJSPdocumentsistointegratetheJSPswithotherXMLtechnologies,suchasXHTML,SVG,orSOAP.Recipe5.5describesJSPdocumentsinmoredetail.Example6-18showsaJSPdocumentversionofExample6-14,usingjsp:includetoincludeafilethatislocatedatthepathWEB-INF/jspf/header_tag.jspf.
Example6-18.AJSPdocumentusingjsp:includetoincludeafile
<jsp:rootxmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:c="http://java.sun.com/jstl/core"
xmlns="http://www.w3.org/1999/xhtml"version="2.0">
<jsp:directive.pagecontentType="text/html"/>
<html>
<jsp:includepage="WEB-INF/jspf/header_tag.jspf"/>
<body>
<h2>WelcometoourPortal<c:outvalue="
${param.fname}"/><jsp:text></jsp:text>
<c:outvalue="${param.lname}"/></h2>
<jsp:useBeanid="dateString"class="java.util.Date"/>
<jsp:text>Thetimeis</jsp:text><c:outvalue="${dateString}"/>.
<br/><br/>
</body>
</html>
</jsp:root>
InExample6-18,theJSPpageincludesthetextthatisreturnedbyheader_tag.jspf.Usingjsp:include,theincludedfiledoesnothavetobewell-formedXMLitself,aslongasitreturnstextthatiswell-formedXMLandfitscorrectlyintotheJSPdocument.
TheJSP2.0specificationrecommendsthatJSPsegmentsthatyouincludeinJSPpagesorJSPdocumentsbegivena.jspfextension.Inaddition,onewaytodifferentiateJSPdocumentsfromconventionalJSPpagesistogivetheJSPdocumentsa.jspxextension(whenusingtheServlet2.4versionofweb.xml).Tomcat4.1.xwillcompileandexecuteasJSPpagesthefileswiththeseextensionsifyouaddtheseservlet-mappingelementstoconf/web.xml:
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jspf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
Example6-19showstheincludedfileheader_tag.jspf.IthasitsowntaglibdirectivesothattheJSTL-relatedtagsinsidetheTITLEtagsproducetheproperoutputfromtherequestparametersfnameandlname.ThecommentatthebottomofExample6-18showsthetextthatisreturnedfromthisJSPsegment,usingjsp:include,whentheenclosingJSPpageisrequestedfromhttp://localhost:8080/home/x617.jspx?fname=Bruce&lname=Perry.
Example6-19.Theincludedfileheader_tag.jspf
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<HEAD>
<METAname="author"content=
"BruceW.Perry,[email protected]"/>
<METAname="keywords"content=
"Java,JSP,servlets,databases,MySQL,Oracle,webdevelopment"/>
<TITLE>ParkerRiver:ThanksForVisiting
<c:outvalue="${param.fname}"/><c:outvalue="${param.lname}"/>
</TITLE>
</HEAD>
<!--sourcetextreturnedfromheader_tag.jspf
<HEAD>
<METAname="author"content=
"BruceW.Perry,[email protected]"/>
<METAname="keywords"content=
"Java,JSP,servlets,databases,MySQL,Oracle,webdevelopment"/>
<TITLE>ParkerRiver:ThanksForVisiting
BrucePerry
</TITLE>
</HEAD>-->
Figure6-9showswhatthecompletedocumentlookslikeinabrowser.
Figure6-9.AJSPdocumentdisplayedinabrowser
Youcanalsousethejsp:directive.includeelement,whichincludesthecontentbeforetheJSPdocumentisconvertedintoaservlet,ratherthanatruntimeaswithjsp:include.ToconvertExample6-17touseanincludedirective,replacethejsp:includeelementwith:
<jsp:directive.includefile="WEB-INF/jspf/header_tag.jspf"/>
Theincludedcontentcannothaveanynon-XMLsyntaxforms,suchasaJSPtaglibdirective,becausetheincludedcodeisincludedverbatimintotheJSPdocumentwhenitisconvertedintoaservlet.
AnalternativeapproachistouseCDATAsectionsintheXMLtoattempttopreservethewordsandsymbolsthatwouldotherwisecausetheXMLfiletofailthewell-formedtest.TheCDATAsectionslooklike<![CDATA[...]]>.
Youwouldhavetoremovethetag-libdirectivefromthetopofExample6-19fortheJSPtocompilecorrectlyusingjsp:directive.include.Inaddition,thec:outtagsinsideofthe
includedsegmentwouldthenbedependentontheinclusionintheenclosingJSPdocumentofanxmlnsattributetomakethecoreJSTLelementsavailable,asinthetopofExample6-18.
AruleofthumbtousewiththetwoincludemechanismsisthatiftheincludedsegmentwillchangefrequentlyandtheenclosingJSPpagemustimmediatelyreflectthosechanges,usejsp:include.Iftheincludedsegmentisrelativelystaticandunchanging,usejsp:directive.include.
SeeAlso
Recipe6.4ontheincludedirective;Recipe6.5onthejsp:includestandardaction;Recipe6.8onincludingcontentfromoutsideofaJSP'scontext;ChapterJSP.1.10.3oftheJSP2.0specificationonincludingfilesinJSPs;Chapter23ontheJSTLtags.
Recipe6.8IncludingContentfromOutsideaContextinaJSP
Problem
YouwanttoincludeaJSPsegmentfromoutsidetheincludingfile'scontext.
Solution
Usethec:importJSTLcoretag.
Discussion
Thec:importtaggivesJSPpageauthorsmuchflexibilityinpullinginresourcesfrominsideandoutsidetheirwebapplication.Thec:importtagallowsapagetoimportwebresources:
FromoutsideJSP'swebcontainer,usinganabsoluteURL(suchashttp://java.sun.com/api).
Fromanothercontextinthesamewebcontainer.Forexample,yourdomainmayincludeacentralrepositoryofincludedcontentathttp://www.mydomain.com/warehouse.AJSPpagethatisinstalledinacontextnamed/customercouldimportaresourcefromthe/warehousecontextbyusing:<c:importurl="/catalog_header.jspf"context="/warehouse"/>
Fromthesamecontext,similartousingjsp:include.
ThisrecipeincludesexamplesofimportingresourcesfromoutsidetheimportingJSP'scontext.Example6-19importsaJSPsegmentheader_tag.jspfromthe/dbprojcontext.Theurlattributespecifiestheresourcetoinclude;thecontextattributedeclaresthecontextfromwhichtheJSPimportstheresource.Tousethec:importtag,theJSPhastoincludeataglibdirectivesuchas:
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
Example6-20includesagroupoftaglibsbyinsertingthetaglib-inc.jspfJSPsegmentinthesecondline.
Example6-20.Usingthec:importtagtoimportanexternalURL
<%@pagecontentType="text/html"%>
<%@includefile="/WEB-INF/jspf/taglib-inc.jspf"%>
<html>
<c:importurl="/header_tag.jspf"context="/dbproj"/>
<body>
<h2>WelcometoourPortal<c:outvalue="
${param.fname}"/><c:outvalue="${param.lname}"/>
</h2>
<jsp:useBeanid="dateString"class="java.util.Date"/>
Thetimeis<c:outvalue="${dateString}"/>.
<br/><br/>
</body>
</html>
Thec:importtaginsertsthetextgeneratedby/dbproj/header_tag.jspinthepartofthecodewherethec:importtagislocated.The/dbprojcontextpathrepresentsadifferentwebapplicationorcontextthantheimportingJSP.Thetopoftheimportingpagenowlookslikethefollowingtext,sincethisistheHTMLthattheimportedfileproduces:
<html>
<HEAD>
<METAname="author"content=
"BruceW.Perry,[email protected]"/>
<METAname="keywords"content=
"Java,JSP,servlets,databases,MySQL,Oracle,webdevelopment"/>
<TITLE>ParkerRiver:ThanksForVisiting
MisterBean
</TITLE>
</HEAD>
<body>
<!--pagecontinuesfromhere...-->
UsingTomcat,thecontextelementinconf/server.xmlhastoincludethisattribute/valuepairortheJSPthatusesc:importwillraiseanexceptionifitattemptstoimportresourcesfromanothercontext:
crossContext="true"<!--"false"bydefault-->
Example6-21importsadescriptionoftheHTTP/1.1protocol,RequestForComments(RFC)2068.
Theexampledeclaresitscontenttypeas"text/plain,"sothatthebrowserdoesnottrytodisplaythetextfileasHTML,whichcanbeunreadablewithplaintextfiles.ThenExample6-21usesataglibdirectivesothattheJSPcanusethec:importtag.Thec:importtagspecifiesthelocationoftheimportedtextfileasanabsoluteURL:http://www.ietf.org/rfc/rfc2068.txt.
Example6-21.Usingc:importtoimportatextresourcewhoseaddressisanabsoluteURL
<%@pagecontentType="text/plain"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<c:importurl="http://www.ietf.org/rfc/rfc2068.txt"/>
IfaJSPusesc:importtoaccessaforbiddenresource(whichwillcausethereceivingservertorespondwithaHTTPstatuscode403),thec:importtagthrowansexceptionandtheJSPcompilationwillfail.
Youcanalsoincludeparameterswithc:importusingnestedc:paramtags.Example6-22importsafileheader_tag.jspf,andmakesavailabletworequestparametersforthatfiletoprocess:fnameandlname.ThetaglibdirectiveatthetopofExample6-22allowstheuseofthec:importandc:paramtagslateroninthecode.
Example6-22.Includingparametervaluesusingc:param
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<c:importurl="WEB-INF/jspf/header_tag.jspf">
<c:paramname="fname"value="Mister"/>
<c:paramname="lname"value="Bean"/>
</c:import>
<body>
<h2>Therestofthepagegoeshere...</h2>
</body>
</html>
Theheader_tag.jspffiletakesthevaluesofthetwoparametersandaddsthemtotheTITLEtag'sgreeting.Example6-23showstheHTMLthatresultsfromthisimportaction.
Example6-23.RequestparametervaluesarereflectedintheHTMLoutput
<html>
<HEAD>
<METAname="author"content=
"BruceW.Perry,[email protected]"/>
<METAname="keywords"content=
"Java,JSP,servlets,databases,MySQL,Oracle,webdevelopment"/>
<TITLE>ParkerRiver:ThanksForVisiting
MisterBean
</TITLE>
</HEAD>
<body>
<h2>Therestofthepagegoeshere...</h2>
</body>
</html>
SeeAlso
Recipe6.1-Recipe6.3onincludingresourcesinservlets;Recipe6.4-Recipe6.7onusingjsp:include,theincludedirective,andincludingresourcesinJSPdocumentsorXMLfiles;Chapter23onUsingtheJSTL1.0;ChapterJSP.5.4oftheJSP2.0specificationonjsp:include;ChapterJSP.1.10.3oftheJSP2.0specificationontheincludedirective.
Chapter7.HandlingWebFormDatainServletsandJSPs
Introduction
Recipe7.1.HandlingaPOSTHTTPRequestinaServlet
Recipe7.2.HandlingaPOSTHTTPRequestinaJSP
Recipe7.3.SettingthePropertiesofaJavaBeaninaJSP
Recipe7.4.SettingaScopedAttributeinaJSPtotheValueofaFormParameter
Recipe7.5.PostingDatafromaServlet
Recipe7.6.PostingDatafromaJSP
Recipe7.7.UsingaServlettoAddaParametertoaQueryString
Recipe7.8.UsingaJSPtoAddaParametertoaQueryString
Recipe7.9.UsingaFiltertoReadParameterValues
Introduction
EverywebdeveloperisfamiliarwiththescenarioinwhichaclientfillsoutanHTMLformandthensubmitstheinsertedinformationtoaserver-sideprogramforprocessing.SomeoftheseprogramsusetheHTTPrequestmethodPOSTtodeliverthedatatotheserver-sideprogram.ThePOSTmethodsendsthedatatotheserverinthebodyoftherequest,ratherthanasaquerystringappendedtoaURL(asintheGETmethod).Forexample,considertheHTMLformtaginExample7-1.
Example7-1.HTMLformtagsetupforpostingdata
<formmethod=POSTaction="/project/controller">
<b>UserName:</b><inputtype="text"name="username"
size="20"><br><br>
<b>Department:</b><inputtype="text"name="department"
size="15"><br><br>
<b>Email:</b><inputtype="text"name="email"
size="15"><br><br>
<inputtype="submit"value="Submit">
</form>
Whentheclientsubmitsthisforminformation,thetopoftheclient'srequesttextlookslikethis:
POST/project/controllerHTTP/1.1
Accept:image/gif,image/x-xbitmap,image/jpeg,image/pjpeg,application/msword,
application/vnd.ms-powerpoint,application/vnd.ms-excel,application/pdf,*/*
Referer:http://localhost:8080/project/login.jsp
Accept-Language:en-us
Content-Type:application/x-www-form-urlencoded
Beneaththistext,afterafewmoreheaders,thebodyoftherequestcarriesthesubmitteddata:
username=Bruce+W+Perry&password=bw_p1968
JSPsandservletsmakeparsingthePOSTdataquitetransparentforthedeveloper.Thisisthetopicofthenextfewrecipes.WethendiscusshowtouseservletsandJSPstopostdatasothattheyessentiallyplaytheroleofclient,insteadofactingasaserver-sideprogram.
Recipe7.1HandlingaPOSTHTTPRequestinaServlet
Problem
YouwanttoprocessdatathatispartofaPOSTrequest.
Solution
UsetheServletRequest.getParameter(Stringname),getParameterMap(),getParameterNames(),orgetParameterValues(Stringname)methodsintheservlet'sdoPostmethod.
Discussion
Theservicemethodofaservletcallstheservlet'sdoPostmethodwhenaclientsendsaPOSTHTTPrequest.Theservletdeveloperthenhasfourdifferentmethodsshecancalltogainaccesstotheposteddata,whichmakesitprettyeasytoprocesstheserequests.JustincaseaclientapplicationusesaGETmethodtosendtheservletitsdataasaquerystring,theservletshouldalsocall:
doPost(request,response);
intheservlet'sdoGet()method.Example7-2demonstrateshandlingPOSTdatawiththeoft-usedgetParameter(Stringname)method,aswellaswiththegetParameterMap()method,whichreturnsajava.util.Map.Themapcontainsparameterkeysandvalues.ThegetParameterNames()methodreturnsa
java.util.Enumerationoftheparameternames.YoucaniteratethroughthisEnumerationandpassthevaluestogetParameter(Stringname).AnotherServletRequestmethod,getParameterValues(Stringname),returnsaStringarrayofallthepostedvaluesforthatparametername(ifthereisonlyonevalue,thereturnedarraycontainsoneString).Figure7-1showsthebrowserdisplayofthePostHandlerservletafterauserhassubmittedtheforminExample7-1.
Figure7-1.Servletdisplaysname/valuepairsfrompostedforminput
Example7-2.UsingtheServletRequest.getParameterandgetParameterMapmethodstohandleposteddata
importjavax.servlet.*;
importjavax.servlet.http.*;
importjava.util.Map;
importjava.util.Iterator;
importjava.util.Map.Entry;
publicclassPostHandlerextendsHttpServlet{
publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throws
ServletException,java.io.IOException{
/*UsetheServletRequest.getParameter(Stringname),getParameterMap(),
getParameterNames(),orgetParameterValues()methodsintheservlet'sdoPostmethod*/
Stringname=request.getParameter("username");
Stringdepart=request.getParameter("department");
Stringemail=request.getParameter("email");
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Welcome</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>YourIdentity</h1>");
out.println(
"Yournameis:"+((name==null||name.equals(""))?
"Unknown":name));
out.println("<br><br>");
out.println(
"Yourdepartmentis:"+((depart==null||depart.equals(""))?
"Unknown":depart));
out.println("<br><br>");
out.println(
"Youremailaddressis:"+((email==null||
email.equals(""))?"Unknown":email));
out.println("<h2>UsingServletRequest.getParameterMap</h2>");
Mapparam_map=request.getParameterMap();
if(param_map==null)
thrownewServletException(
"getParameterMapreturnednullin:"+
getClass().getName());
//iteratethroughthejava.util.Mapanddisplaypostedparameter
//values
//thekeysoftheMap.EntryobjectsaretypeString;thevaluesare
//typeString[],
//orStringarray
Iteratoriterator=param_map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entryme=(Map.Entry)iterator.next();
out.println(me.getKey()+":");
String[]arr=(String[])me.getValue();
for(inti=0;i<arr.length;i++){
out.println(arr[i]);
//printcommasaftermultiplevalues,
//exceptforthelastone
if(i>0&&i!=arr.length-1)
out.println(",");
}//endfor
out.println("<br><br>");
}//endwhile
out.println("</body>");
out.println("</html>");
}
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
doPost(request,response);
}
}
Gettingthevalueofaparameterisassimpleasusingrequest.getParameter(parametername).ThenyoucantestforthefailuretoreturnavalidvaluewithcodefromExample7-2:
out.println("Yournameis:"+
((name==null||name.equals(""))?"Unknown":name));
IfthenamevariableisanemptyStringornull,thentheservletprints"Unknown";otherwise,itprintsthenamevalue.Thereareseveraldesignpatternsyoucanuseforvalidatingforminput,includingclient-sideJavaScriptandspecialvalidationJavaBeans.
Handlingthejava.util.Maptypeismoreinvolvedandentailsmorecode.TheservletgetstheparametermapbycallingtheServletRequestmethod:
Mapparam_map=request.getParameterMap()
Thenthecodegetsajava.util.Iteratorfromthejava.util.SetreturnedfromMap.entrySet().TheSetcontainsMap.Entryobjects,whicharekey/valuepairsrepresentingtheparameternameandvalue.Theservletusestheiteratortocyclethroughtheparameternamesandvalues:
Iteratoriterator=param_map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entryme=(Map.Entry)iterator.next();
out.println(me.getKey()+":");
//ThereturnedvalueisaStringarray
String[]arr=(String[])me.getValue();
for(inti=0;i<arr.length;i++){
out.println(arr[i]);
//printcommasaftermultiplevalues,
//exceptforthelastone
if(i>0&&i!=arr.length-1)
out.println(",");
}//endfor
out.println("<br><br>");
}//endwhile
Ifthislookstooelaborateforprocessingposteddata,thenreservegetParameterMap()forapplicationsthataredesignedtodealwiththem,suchasavalidatorbeanthattakesaMapasaconstructorormethodparameter.Inaddition,Recipe7.2showsaJSPthatusesJSTLtoconvenientlyprocessaparametermap.
SeeAlso
Recipe7.2onhandlingaPOSTrequestinaJSP;Recipe7.5onpostingdatafromaservlet;Recipe7.7onusingaservlettoaddaparametertoaquerystring;theServletRequestAPIdocsathttp://java.sun.com/j2ee/1.4/docs/api/index.html.
Recipe7.2HandlingaPOSTHTTPRequestinaJSP
Problem
YouwanttohaveaJSPhandlethedatapostedfromaformorclientapplication.
Solution
UsetheJSTLc:forEachtagtoiterateovertheparameternamesandvalues.
Discussion
TheJSTLmakesitveryeasytoprocessinputdatafromaPOSTmethod.TheJSPinExample7-3usesonlytemplatetextandJSTLtagstodisplaypostedinformation.Thec:forEachtagiteratesovertheposteddatausingtheimplicitJSTLobjectparam.Theparamobjectcontainsjava.util.Map.Entrytypes,whicheachholdakey/valuepair.Thekeyandvaluecorrespondtothenameofasubmittedparameteranditsvalue,suchas"department=Development."UsingtheExpressionLanguage(EL),thesyntax"${map_entry.key}"or"${map_entry.value}"istheequivalentofcallingtheMap.Entry.getKey()andgetValue()methods.Thereturnvaluesofthesemethodcallsarefedtothec:outJSTLtagfordisplayintheHTMLpage.Figure7-2showswhatthebrowserpagelookslikeiftheformsubmittedtotheJSPistheonedetailedinExample7-1.Withyourtaglib,useaurivalueofhttp://java.sun.com/jsp/jstl/coreforJSTL1.1.
Example7-3.IteratingposteddatawiththeJSTL
<%@pagecontentType="text/html"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>PostDataViewer</title></head>
<body>
<h2>Hereisyourposteddata</h2>
<c:forEachvar="map_entry"items="${param}">
<strong><c:outvalue="${map_entry.key}"/></strong>:
<c:outvalue="${map_entry.value}"/><br><br>
</c:forEach>
</body>
</html>
MakesuretoincludethetaglibdirectivewhenyouareusingtheJSTLtags.ThetaglibinExample7-3takescareofanyofthecustomtagswiththe"c"prefix,asinc:forEach.
Chapter23explainshowtoinstalltheJSTLinyourwebapplication,makedifferentcustomtags,andusetheEL.
Figure7-2.AJSPdisplayingpostedname/valuepairs
Ifyouwanttogetthevaluesofparameterswithoutusingac:forEachtag,thenusethecodefragmentinExample7-4.Thiscodedisplaysthevaluesofparameterswhentheparameternamesareknownbythedeveloper(whichisusuallythecase).
Example7-4.Displayingindividualparametervaluesusingc:out
<h2>Hereisyourposteddata</h2>
<strong>Username:</strong>:<c:outvalue="${param.username}"/>
<br><br>
<strong>Department:</strong>:<c:outvalue="${param.department}"/>
<strong>Email:</strong>:<c:outvalue="${param.email}"/>
SubstitutingthiscodeintotheJSPproducesthesameresultsasthoseshownFigure7-2.
TheJSP2.0specificationisdesignedtoallowtheuseoftheELintemplatetextinotherwords,withoutthec:outJSTLtag.
SeeAlso
Recipe7.2onhandlingaPOSTrequestinaJSP;Recipe7.3onsettingthepropertiesofaJavaBeantoforminput;Recipe7.4onsettingascopedattributetothevalueofaparameter;Recipe7.6onpostingdatafromaJSP;Chapter23onusingtheJSTL.
Recipe7.3SettingthePropertiesofaJavaBeaninaJSP
Problem
YouwanttosetaJavaBean'spropertiestothevaluesenteredinaform.
Solution
Usethejsp:setPropertystandardaction,withitspropertyattributesetto"*"anditsclassattributesettothefullyqualifiedclassnameoftheJavaBean.
Discussion
Thejsp:setPropertystandardactionhasabuilt-inmethodforautomaticallymappingthevaluessubmittedinaformtoaJavaBean'sfieldsorvariables.ThenamesofthesubmittedparametershavetocorrespondtothenamesoftheJavaBean'ssettermethods.Example7-5showsasetBean.jsppagethatreceivesdatafromanHTMLform:
<formmethod=postaction="http://localhost:8080/home/setBean.jsp">
TheJSPfirstinstantiatesanobjectofthetypecom.jspservletcookbook.UserBeanusingjsp:useBean.Thenitsetsthepropertiesofthebeanusingjsp:setProperty.Thenameattributeofjsp:setPropertymatchestheidattributeofjsp:useBean.Thepropertyattributeofjsp:setPropertyissimplysetto"*".
Example7-5.beanSet.jspJSPthatsetstheUserBean'spropertieswithforminput
<%@pagecontentType="text/html"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="userB"class="com.jspservletcookbook.UserBean">
<jsp:setPropertyname="userB"property="*"/>
</jsp:useBean>
<html>
<head><title>PostDataViewer</title></head>
<body>
<h2>Hereisyourposteddata</h2>
<strong>Username</strong>:
<c:outvalue="${userB.username}"/><br><br>
<strong>Department</strong>:
<c:outvalue="${userB.department}"/><br><br>
<strong>Email</strong>:
<c:outvalue="${userB.email}"/>
</body>
</html>
Example7-5usesthec:outelementoftheJSTLtodisplaythebean'svariousvaluesinabrowserpage.Thevalueattributeofc:outusestheELtoacquireapropertyvalue,asin"${userB.email}".ThissyntaxistheequivalentofcallingtheUserBean'sgetEmail()method.Example7-6showstheUserBean,whichusestheJavaBeannamingconventionstoensurethatitspropertiescanbeproperlysetandaccessed.Figure7-3showsthebrowserdisplayofthevalues.
Figure7-3.DisplayingforminputviaaJavaBean
Thejsp:setPropertyaction,asusedinthisrecipe,setstheJavaBean'spropertiesbyusingintrospectiontolineupparameternameswiththebean'ssettermethods.Ifthebeanhasafieldnamed"Username,"thentheparameternamemustbeexactly"Username"andthesettermethodmustbeexactly"setUsername(Stringname)"(ifthebean'sfieldisaString).Watchout,it'scase-sensitive!
Example7-6.EncapsulatingtheposteddatainaJavaBean
packagecom.jspservletcookbook;
publicclassUserBeanimplementsjava.io.Serializable{
Stringusername;
Stringemail;
Stringdepartment;
publicUserBean(){}
publicvoidsetUsername(String_username){
if(_username!=null&&_username.length()>0)
username=_username;
else
username="Unknown";
}
publicStringgetUsername(){
if(username!=null)
returnusername;
else
return"Unknown";}
publicvoidsetEmail(String_email){
if(_email!=null&&_email.length()>0)
email=_email;
else
email="Unknown";
}
publicStringgetEmail(){
if(_email!=null)
returnemail;
else
return"Unknown";}
publicvoidsetDepartment(String_department){
if(_department!=null&&_department.length()>0)
department=_department;
else
department="Unknown";
}
publicStringgetDepartment(){
if(department!=null)
returndepartment;
else
return"Unknown";}
}
Recipe7.4showshowtouseabeantovalidateforminput,thensetascopedattributetotheinput.
SeeAlso
Recipe7.2onhandlingaPOSTrequestinaJSP;Recipe7.4onsettingascopedattributetothevalueofaparameter;Recipe7.6onpostingdatafromaJSP;Chapter23onusingtheJSTL.
Recipe7.4SettingaScopedAttributeinaJSPtotheValueofaFormParameter
Problem
Youwanttosetarequest-,session-,orapplication-scopedattributetoavaluethataclienthassubmittedaspartofforminput.
Solution
Usethejsp:useBeanandjsp:setPropertystandardactionstosetaJavaBean'spropertytothesubmittedvalue.Thenusethec:setJSTLcustomtagtosettheattributetothevalidatedvalue.
Discussion
Somewebapplicationsmayvalidateforminputsuchasanemail/passwordcombination,thensetarequest-,session-,orapplication-scopedattributetothevalidatedvalue.AnefficientwaytohandleimportantdatathatausersubmitsistouseaJavaBeanwhosepurposeistovalidatethesubmissionagainstsomebusinessruleorexternalresource,suchasadatabase.Ifthesubmissionisvalid,thentheapplicationcreatesasessionattribute,forinstance,withthevalue.Ifthesubmissionisinvalid,thenabooleanvariableintheJavaBeanissettofalse.TheJSPtowhichtheforminputissentcancheckthisvaluebeforeithandlesthedataasvalid.
Example7-7showsaClientValidatorbeanthathasthreefields:email,password,andvalid.ThisbeanisusedbyaJSPtovalidateforminputbeforetheJSPsetsrequest-scopedattributestothesubmitted
values.
Example7-7.TheClientValidatorbean
packagecom.jspservletcookbook;
publicclassClientValidatorimplementsjava.io.Serializable{
Stringemail;
Stringpassword;
booleanvalid;
publicClientValidator(){
this.valid=false;}
publicbooleanisValid(){
/*UseaDataAccessObjecttovalidatetheemailandpassword.
Ifthevalidationdoesnotfail,thensetthis.validtotrue*/
this.valid=true;
returnvalid;
}
publicvoidsetEmail(String_email){
if(_email!=null&&_email.length()>0)
email=_email;
else
email="Unknown";
}
publicStringgetEmail(){
returnemail;
}
publicvoidsetPassword(String_password){
if(_password!=null&&_password.length()>0)
password=_password;
else
password="Unknown";
}
publicStringgetPassword(){
returnpassword;}
}
Example7-8istheJSPthatusesClientValidator.TheJSPfirstusesjsp:useBeantocreateaninstanceofthebean.ThenitsetsthefieldsorpropertiesofthebeantothevaluesthathavebeenpostedtotheJSP,whichare"email"and"password".IftheisValidbeanpropertyistrue,whichistestedwiththisJSTLcode:
<c:iftest="${isValid}">
thentheJSPsetstworequest-scopedattributes.Theattributesarenowavailabletoapagethatisforwardedthisrequest.SessionattributesareaccessiblefromservletsandJSPsthatareassociatedwiththesamesession(seeChapter11).Theapplicationscopeencompassesthecontextorwebapplication.
Ifyouwanttosetsession-orapplication-scopedattributes,changethecodeinExample7-8to:
<c:setvar="email"value="${chk.email}"
scope="session"/>
<c:setvar="password"value="${chk.password}"
scope="session"/>
or:
<c:setvar="email"value="${chk.email}"
scope="application"/>
<c:setvar="password"value="${chk.password}"
scope="application"/>
Example7-8.validChk.jsppagethatusesavalidatorbeantocheckforminputdata
<%@pagecontentType="text/html"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="chk"class="com.jspservletcookbook.ClientValidator">
<jsp:setPropertyname="chk"property="*"/>
</jsp:useBean>
<%--getvalidpropertyfromClientValidatorbean--%>
<c:setvar="isValid"value="${chk.valid}"/>
<c:iftest="${isValid}">
<c:setvar="email"value="${chk.email}"scope="request"/>
<c:setvar="password"value="${chk.password}"scope="request"/>
</c:if>
<html>
<head><title>ClientChecker</title></head>
<body>
<h2>Welcome</h2>
<strong>Email</strong>:
<c:outvalue="${email}"/><br><br>
<strong>Password</strong>:
<c:outvalue="${password}"/>
</body>
</html>
SeeAlso
Recipe7.2onhandlingaPOSTrequestinaJSP;Recipe7.3onsettingthepropertiesofaJavaBeantoforminput;Recipe7.6onpostingdatafromaJSP;Chapter23onusingtheJSTL.
Recipe7.5PostingDatafromaServlet
Problem
YouwanttosendparametersandtheirvaluesasaPOSTrequestfromaservlet.
Solution
UsetheJakartaCommonsHttpClientcomponentanditsPostMethodclasstoautomatethepostingofdatatootherprograms.
Discussion
TheJakartaCommonsHttpClientisacomponentthatallowsthedevelopertomimicthefeaturesofawebbrowserinhisJavacode,suchassendingGETandPOSTHTTPrequests,aswellasusingHTTPSforsecuresockets.Asthehomepagedescribesthisusefulcomponent,HttpClient"providesanefficient,up-to-date,andfeature-richpackageimplementingtheclientsideofthemostrecentHTTPstandardsandrecommendations"(http://jakarta.apache.org/commons/httpclient/).HttpClientisofferedundertheApacheSoftwareLicense.
ThisrecipedescribesusingHttpClienttopostdatatoanotherserver-sideprogramusingthePOSTHTTPmethod.First,downloadtheHttpClientdistributionfromtheJakartasite(http://jakarta.apache.org/commons/httpclient/downloads.html).ThenunpackthedistributionandplacetheJARfilethatitcontainsintheWEB-INF/libdirectoryofyourwebapplication.Atthiswriting,theJARforRelease2.0Alpha3wascommons-httpclient-2.0-alpha2.jar.Onceyou
havetakencareofthisinstallation,yourservletsandbeanscanusetheHttpClientclasses.
Example7-9isaservletthatpostsdatatoaJSP:http://localhost:8080/home/viewPost.jsp.Example7-3showstheviewPost.jspfile.Notetheclassesfromtheorg.apache.commons.httpclientpackagethattheservlethastoimportatthetopofthecode.
Example7-9.AservletthatpostsdatatoaJSPusingHttpClient
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
importorg.apache.commons.httpclient.HttpClient;
importorg.apache.commons.httpclient.HttpStatus;
importorg.apache.commons.httpclient.methods.PostMethod;
importorg.apache.commons.httpclient.NameValuePair;
publicclassClientPostextendsHttpServlet{
publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
HttpClienthttpClient=newHttpClient();
PostMethodpostMethod=newPostMethod(
"http://localhost:8080/home/viewPost.jsp");
NameValuePair[]postData={
newNameValuePair("username","devgal"),
newNameValuePair("department","development"),
newNameValuePair("email","[email protected]")
};
//the2.0beta1versionhasa
//PostMethod.setRequestBody(NameValuePair[])
//method,asaddParametersisdeprecated
postMethod.addParameters(postData);
httpClient.executeMethod(postMethod);
//displaytheresponsetothePOSTmethod
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
//A"200OK"HTTPStatusCode
if(postMethod.getStatusCode()==HttpStatus.SC_OK){
out.println(postMethod.getResponseBodyAsString());
}else{
out.println("ThePOSTactionraisedanerror:"+postMethod.getStatusLine());
}
//releasetheconnectionusedbythemethod
postMethod.releaseConnection();
}
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
doPost(request,response);
}
}
Thecodesendsthreename/valuepairstotheJSP(namedusername,
department,andemail),whichwillhandletheposteddata.HttpClienthandlesthereturnedtextfromthePOSTmethodsothatyoucandisplayitinthesameservlet.IfyouexpecttoreceivelargeamountsoftextasreturnvaluesfromthePOST,thenconsiderusingtheHttpMethodBase.getResponseBodyAsStream()methodinsteadofgetResponseBodyAsString().ThegetResponseBodyAsStream()methodreturnsajava.io.InputStream.Example7-9isderivedfromsamplecodeprovidedattheHttpClientwebsite.
Figure7-4showsthewebbrowserdisplayafterrequestingtheClientPostservlet.
Figure7-4.Displayingthereturnedtextafterpostingdatafromaservlet
SeeAlso
Recipe7.1onhandlingaPOSTrequestinaservlet;Recipe7.7onusingaservlettoaddaparametertoaquerystring;theJakartaCommonsHttpClientpage:http://jakarta.apache.org/commons/httpclient.
Recipe7.6PostingDatafromaJSP
Problem
YouwanttosendparametersandtheirvaluesasanHTTPPOSTrequestfromaJSP.
Solution
TheeasiestwaytopostdatafromaJSPistodoittheoldfashionedway:usetheHTMLformtagandaSubmitbutton.Ifyouhavetosendthedatadynamically(asinnotrelyingonausertopressaformbutton),useaJavaBeanthatencapsulatestheHttpClientcodediscussedinRecipe7.5.
Discussion
ThesimplestwaytoinitiateaPOSTmethodinaJSPistosetuptheHTMLtemplatetextasshowninExample7-1:provideanHTMLformtagthattheuserfillsoutandsubmits.SinceExample7-1alreadyshowsatypicalHTMLform,I'lusethisspacetoshowaJavaBeanthatallowsaJSPtodynamicallypostdatatoanotherserver-sideprocess.
Example7-10showsajspPost.jsppagethatusesaPostBeanutilityclasstosendasetofparameters/valuestoanotherJSP.ThereceivingJSP,viewPost.jsp,processestheparametersthatthePostBeanobjectsendsit,thenreturnssometextfortheJSPinExample7-10todisplay.TheJSPpassestheparametersthatitwantstopostasajava.util.MaptothePostBeanclass.ThePostBeanurlpropertyisthedestinationfortheposteddata(theaddressthatyouwould
otherwiseplaceintheactionattributeofaformHTMLtag).Thecode:
<jsp:setPropertyname="postBean"property="parameters"value="<%=request.
getParameterMap()%>"/>
getsaMapoftheparametersthatwerepassedtothejspPost.jsppagewiththeHttpServletRequest.getParameterMap()method,thenpassesthatMaptothePostBeanclasstobereposted.
Example7-10.AJSPthatpostsparametersandvaluesdynamically
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%--createaninstanceofthePostBeanclassifoncedoesnotexist--%>
<jsp:useBeanid="postBean"class="com.jspservletcookbook.PostBean"/>
<%--setthePostBeanparameterspropertytoaMaptype--%>
<jsp:setPropertyname="postBean"property="parameters"value="<%=request.
getParameterMap()%>"/>
<jsp:setPropertyname="postBean"property="url"value="http://localhost:8080/home/
viewPost.jsp"/>
<%--Posttheparametersanddisplaythereturnedtext--%>
<jsp:getPropertyname="postBean"property="post"/>
Example7-11showsthePostBeanclassthattheJSPpageusestopostdata.ThisbeanusestheJakartaCommonsHttpClientcomponenttosendanHTTPPOSTrequest.ThesendingactionhappensinthePostBean.getPost()method,whichsendsofftheparametersandreturnsthetextresultfromthereceivingservlet(inthisexample,it'sviewPost.jsp).BecausethebeanmethodiscalledgetPost(),usingtheJavaBeannamingconventionsformethodsthatreturnpropertyvalues,wecancallthemethodintheJSPwith:
<jsp:getPropertyname="postBean"property="post"/>
ThelattercodeisthenreplacedwiththeStringreturnvalue.
Example7-11.Adata-postingJavaBeanforusebyaJSPorservlet
packagecom.jspservletcookbook;
importjava.util.Map;
importjava.util.Iterator;
importjava.util.Map.Entry;
importorg.apache.commons.httpclient.HttpClient;
importorg.apache.commons.httpclient.HttpStatus;
importorg.apache.commons.httpclient.methods.PostMethod;
importorg.apache.commons.httpclient.NameValuePair;
importorg.apache.commons.httpclient.HttpException;
publicclassPostBeanimplementsjava.io.Serializable{
privateMapparameters;
privateStringurl;
publicPostBean(){
}
publicvoidsetParameters(Mapparam){
if(param!=null)
parameters=param;
}
publicMapgetParameters(){
returnparameters;
}
publicvoidsetUrl(Stringurl){
if(url!=null&&!(url.equals("")))
this.url=url;
}
publicStringgetUrl(){
returnurl;
}
publicStringgetPost()throwsjava.io.IOException,HttpException{
if(url==null||url.equals("")||parameters==null)
thrownewIllegalStateException(
"InvalidurlorparametersinPostBean.getPostmethod.");
StringreturnData="";
HttpClienthttpClient=newHttpClient();
PostMethodpostMethod=newPostMethod(url);
//converttheMappassedintothebeantoaNameValuePair[]type
NameValuePair[]postData=getParams(parameters);
//the2.0beta1versionhasa
//PostMethod.setRequestBody(NameValuePair[])
//method,asaddParametersisdeprecated
postMethod.addParameters(postData);
httpClient.executeMethod(postMethod);
//A"200OK"HTTPStatusCode
if(postMethod.getStatusCode()==HttpStatus.SC_OK){
returnData=postMethod.getResponseBodyAsString();
}else{
returnData="ThePOSTactionraisedanerror:"+
postMethod.getStatusLine();
}
//releasetheconnectionusedbythemethod
postMethod.releaseConnection();
returnreturnData;
}//endgetPost
privateNameValuePair[]getParams(Mapmap){
NameValuePair[]pairs=newNameValuePair[map.size()];
//UseanIteratortoputname/valuepairsfromtheMap
//intothearray
Iteratoriter=map.entrySet().iterator();
inti=0;
while(iter.hasNext()){
Map.Entryme=(Map.Entry)iter.next();
//Map.Entry.getValue()returnsaString[]arraytype
pairs[i]=newNameValuePair(
(String)me.getKey(),((String[])me.getValue())[0]);
i++;
}
returnpairs;
}//endgetParams
}
ThedisplayedresultslooksexactlylikeFigure7-5,whichalsousesviewPost.jsptoshowthename/valuepairsthatwerefedtotheJSP.Again,ifyouhavetouseaJSPtodynamicallymimicanHTMLform,itisagoodideatodelegatethemechanicsofpostingdatatoaJavaBeansothattheJSPremainsapresentationcomponentandthebeancanbereusedelsewhere.
Figure7-5.DisplayingparametersaddedfromaforwardingJSP
SeeAlso
Recipe7.2onhandlingaPOSTrequestinaJSP;Recipe7.3onsettingthepropertiesofaJavaBeantoforminput;Recipe7.8onusingaJSPto
addaparametertoaquerystring.
Recipe7.7UsingaServlettoAddaParametertoaQueryString
Problem
Youwanttouseaservlettoaddoneormoreparameterstoaquerystring,thenforwardtherequesttoitsfinaldestination.
Solution
UsetheHttpServletRequestAPItogettheexistingquerystring.Thenappendanynewparameterstothequerystringanduseajavax.servlet.RequestDispatchertoforwardtherequest.
Discussion
TheservletinExample7-12simplytakesanyexistingquerystringandappendstheparametersthatithastoaddtothisString.Thenitsendsthenowextended(ornew)querystringonitsmerrywaywithacalltoRequestDispatcher.forward.
Example7-12.Addingaparametertoaquerystringwithaservlet
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassQueryModifierextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//returnsnulliftheURLdoesnotcontainaquerystring
Stringquerystr=request.getQueryString();
if(querystr!=null){
querystr=querystr+
"&inspector-name=Jen&[email protected]";
}else{
querystr="inspector-name=Jen&[email protected]";}
RequestDispatcherdispatcher=
request.getRequestDispatcher("/viewPost.jsp?"+querystr);
dispatcher.forward(request,response);
}
publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
doGet(request,response);
}
}
TheHttpServletRequest.getQueryString()methodreturnsthequerystringwithouttheopening"?",asin:
first=Bruce&last=Perry&zipcode=01922
IfyouwanttogettherequestURLrightuptothequerystringbutnotincludethe
"?",useHttpServletRequest.getRequestURL(),whichreturnsajava.lang.StringBuffertype.
SeeAlso
Recipe7.1onhandlingaPOSTrequestinaservlet;Recipe7.5onpostingdatafromaservlet.
Recipe7.8UsingaJSPtoAddaParametertoaQueryString
Problem
YouwanttouseaJSPtoaddoneormoreparameterstoaquerystring,thenforwardtherequesttoitsdestination.
Solution
Usethejsp:forwardandjsp:paramstandardactions.
Discussion
AddingoneormoreparametersandforwardingtoanothercomponentisaseasyasfourlinesinaJSP.Thejsp:forwardactionaddsanyjsp:paramstoexistingparameterswhenitforwardsthistexttotheprocessingcomponent,asshowninExample7-13.
Example7-13.AddingparametersandforwardinginaJSP
<jsp:forwardpage="/viewPost.jsp">
<jsp:paramname="inspector-name"value="Jen"/>
<jsp:paramname="inspector-email"value="[email protected]"/>
</jsp:forward>
IfthisJSPisrequestedwiththefollowingURL:
http://localhost:8080/home/addParam.jsp?first=Bruce&last=Perry&zip=01922
thenthethreeoriginalparameters(first,last,andzip)arepreservedwhenthejsp:forwardactionaddstwoadditionalparameters(inspector-name,inspector-email)andforwardsthepage.Intheexample,thepageisprocessedbytheviewPost.jsppageshowninExample7-3.RequestingaddParam.jspinabrowserforwardstherequest,andatotaloffiveparameterstotheviewPost.jsppage.Figure7-5showstheresultinabrowser.
SeeAlso
Recipe7.2onhandlingaPOSTrequestinaJSP;Recipe7.3onsettingthepropertiesofaJavaBeantoforminput;Recipe7.6onpostingdatafromaJSP.
Recipe7.9UsingaFiltertoReadParameterValues
Problem
Youwanttouseafiltertointerceptforminputandreadit.
Solution
UsethevariousgetParametermethodsoftheServletRequestAPItotakealookatparametervaluesinafilter.
Discussion
Whenyoudevelopafilterforaservlet,yourfilterclasshastoimplementthejavax.servlet.Filterinterface.ThismeansthatyourFilterclasshastoimplementthedoFilter(request,response)anddestroy()methodsofthatinterface.ThedoFiltermethodcontainsthehooktothefilteredservlet'sparametervalues.ThedoFilter'sServletRequestparameterhasthegetParameter,getParameterMap,getParameterNames,andgetParameterValuesmethodswhichallowthefiltertopeekataservlet'sparametersandvalues.
First,youhavetomaptheFilteryouhavedesignedtotheservlet.Thischunkofweb.xmlmapsaFilterobjecttoaservletnamedViewer.
<!--anycontext-paramelementsgohere-->
<filter>
<filter-name>ParamSnoop</filter-name>
<filter-class>com.jspservletcookbook.ParamSnoop</filter-class>
</filter>
<filter-mapping>
<filter-name>ParamSnoop</filter-name>
<servlet-name>Viewer</servlet-name>
</filter-mapping>
<!--web.xmlcontinues-->
PlacethefilterclassintheWEB-INF/classesdirectoryofyourwebapplication,orinsideaJARfilethatisplacedinWEB-INF/lib.Theservletcontainercreatesaninstancewhenthecontainerstartsupofeachfilterthatisdeclaredinweb.xml.Thecontainerthenexecutesthefilter(callsitsdoFiltermethod)whenauserrequestsanyoftheservletsthefilterismappedto.SotheParamSnoopfiltercaninspectarequestmadetotheViewerservletbeforetheservletprocessestherequest.
"OnlyoneinstanceperfilterdeclarationinthedeploymentdescriptorisinstantiatedperJavavirtualmachineofthecontainer,"accordingtotheServletv2.4specification,ChapterSRV.6.2.1.
Example7-14getsaccesstotheparametersintheinterceptedrequestbycallingServletRequest.getParameterMap().However,youarefreetouseotherServletRequestAPImethodstolookatparameters,suchasgetParameterStringName.ThegetParameterMap()methodreturnsajava.util.Mapofparameternamesandvalues,whichyouextractfromtheMapusingajava.util.Iteratoranditsnext()method.
ThecallMap.entrySet()returnsajava.util.Set,fromwhichyouobtainanIteratorbycallingSet.iterator().TheobjectsreturnedfromtheIterator.next()methodinthiscaseareMap.Entryobjectsthathold
key/valuepairs,relatingtotheparameternamesandvalues.
Example7-14alsoshowshowtopullthekey/valuepairsoutofthemapandlogthevaluesusingtheServletContext.log()method.
Example7-14.Snoopingonparametervalueswithaservlet
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjava.util.Map;
importjava.util.Iterator;
importjava.util.Map.Entry;
publicclassParamSnoopimplementsFilter{
privateFilterConfigconfig;
/**CreatesnewParamSnoop*/
publicParamSnoop(){
}
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
this.config=filterConfig;
}
publicvoiddoFilter(
ServletRequestrequest,ServletResponseresponse,FilterChainchain)
throwsjava.io.IOException,ServletException{
MapparamMap=request.getParameterMap();
ServletContextcontext=config.getServletContext();
/*usetheServletContext.logmethodtolog
paramnames/values*/
context.log("doFiltercalledin:"+config.getFilterName()+
"on"+(newjava.util.Date()));
context.log("Snoopingtheparametersinrequest:"+
((HttpServletRequest)request).getRequestURI());
Iteratoriter=paramMap.entrySet().iterator();
while(iter.hasNext()){
Map.Entryme=(Map.Entry)iter.next();
context.log((String)me.getKey()+":"+
((String[])me.getValue())[0]);
}
//continuetherequest,responsetonextfilterorservlet
//destination
chain.doFilter(request,response);
}
publicvoiddestroy(){
/*calledbeforetheFilterinstanceisremoved
fromservicebythewebcontainer*/
}
}
TheonlyreasonweusedtheServletContext.log()methodwastodisplaytheinspectionofparametersbythefilter.HereisanexampleoftheTomcatlogin<Tomcat-installation-directory>/logsshowingthetwoparametersthatwerestoredintheservletrequest(last,first).Inotherwords,thewebbrowserrequestwashttp://localhost:8080/home/viewer?first=Bruce&last=Perry.
2003-04-1317:13:33doFiltercalledin:ParamSnooponSunApr1317:13:33EDT2003
2003-04-1317:13:33Snoopingtheparametersinrequest:/home/viewer
2003-04-1317:13:33last:Perry
2003-04-1317:13:33first:Bruce
SeeAlso
Recipe7.1onhandlingaPOSTrequestinaservlet;Recipe7.7onusingaservlettoaddaparametertoaquerystring;Chapter19onfilteringrequestsandresponses;ChapterSRV.6onFiltersintheServlet2.4specification.
Chapter8.UploadingFilesIntroduction
Recipe8.1.PreparingtheHTMLPageforFileUploads
Recipe8.2.Usingthecom.oreilly.servletLibrary
Recipe8.3.UploadingOneFileataTime
Recipe8.4.UploadingMultipleFiles
Recipe8.5.RenamingFiles
Recipe8.6.UsingaJSPtoHandleaFileUpload
Introduction
WebsitesusetheHTMLformtagtoallowuserstosubmitfilesfromtheirownfilesystemforprocessingontheserver.Theformtagenablestheuploadingactionwithanestedinputelementthathasatypeattributesetto"file".TheformandinputtagisspecifiedusingthesyntaxdescribedinRecipe8.1.
TheHTTPrequestforfileuploadingusesacontenttypeof"multipart/form-data".TheHTTPmessagethattheusersendstotheserverbyclickingthewebpage'sSubmitbuttoncontainsdescriptiveheadersandthebodyofeachuploadedfile.Eachoftheuploadedfilesisseparatedbyaspecifiedboundarypattern(seetheContent-TypeheadervalueinExample8-1).Example8-1showsanabbreviatedviewofa"multipart/form-data"typerequestincludingtheuploadingofthreeverysmallfiles.Tomakethisexamplemorecompact,IhaveremovedsomeofthevaluesfromtheAcceptrequestheader.
Example8-1.AnHTTPrequestmessagewiththreeuploadedfiles
POST/home/upload.jspHTTP/1.1
Accept:image/gif,image/x-xbitmap,image/jpeg,image/pjpeg...
Referer:http://localhost:8080/home/interact.html
Accept-Language:en-us
Content-Type:multipart/form-data;boundary=---------------------------7d33c11c6018e
Accept-Encoding:gzip,deflate
User-Agent:Mozilla/4.0(compatible;MSIE5.5;WindowsNT4.0)
Host:localhost:9000
Content-Length:541
Connection:Keep-Alive
Cache-Control:no-cache
Cookie:JSESSIONID=7F6154184FFF3D1AE345E1F2FFF1A22E
-----------------------------7d33c11c6018e
Content-Disposition:form-data;name="file1";filename="H:\home\file1.txt"
Content-Type:text/plain
Thisisfile1.
-----------------------------7d33c11c6018e
Content-Disposition:form-data;name="file2";filename="H:\home\file2.txt"
Content-Type:text/plain
Thisisfile2.
-----------------------------7d33c11c6018e
Content-Disposition:form-data;name="file3";filename="H:\home\file3.txt"
Content-Type:text/plain
Thisisfile3.
-----------------------------7d33c11c6018e--
TheHTTPrequestdelineateseachuploadedfilewithaboundarypattern:
-----------------------------7d33c11c6018e.
EachofthefileshasaContent-DispositionandContent-Typeheader.ThesimpletextfilesthatExample8-1uploadstotheserverhaveonlyonelineeachtogiveyouaclearsnapshotofwhatthistypeofHTTPrequestlookslike.Formoredetailsonthefile-uploadingmechanismitself,seeRFC1867:http://www.ietf.org/rfc/rfc1867.txt.
Recipe8.1PreparingtheHTMLPageforFileUploads
Problem
YouwanttosetupanHTMLpagetoallowtheusertospecifyafilefromhisfilesystemtouploadtotheserver.
Solution
UsetheHTMLformtagwithitsenctypeattributesetto"multipart/form-data".Useaninputtagnestedintheformtagwithatypeattributeof"file".
Discussion
TheHTMLforfileuploadinginvolvesafew"musthaves."Theformtagspecifiestheservlet(orotherserver-sidecomponent)thatishandlingthefileuploadinitsactionattribute.ThemethodattributemustbePOST(notGET)forthefileuploadactiontowork.Theformtag'senctypeattributemustbe"multipart/form-data".
Thewidgetwithwhichtheuserentersthefiletouploadisaninputtagwithatypeof"file",andlookslikeatextfield.Thenameattributeuniquelynamestheparticularinputtag,whichbecomesimportantwhentheHTMLspecifiestheuploadingofmorethanonefile(seethenoteattheendofthisrecipe).Withoutanyadditionalintervention,theserversavestheuploadedfilewithitsoriginalfilename.Theacceptattributeisdesignedtolimitthefiletypesthattheusercanchooseforuploading,suchastothe"application/pdf"MIMEtype,butthisattribute
haspoorsupportamongbrowsers.
WhendisplayingtheHTMLinExample8-2,browsersautomaticallyshowaBrowsebutton.Whentheformclientselectsthebutton,thebrowserdisplaysatypicalfilesystemnavigationwindowwithwhichtheusercanselectthefile.
Example8-2.SimpleHTMLforfileuploading
<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.0Transitional//EN">
<html>
<head>
<title>PleaseChooseTheFile</title>
</head>
<bodybgcolor="#ffffff">
<tableborder="0"><tr>
<formaction="/home/servlet/com.jspservletcookbook.UploadServlet"method="post"
enctype="multipart/form-data">
<tdvalign="top"><strong>Pleasechooseyourdocument:</strong><br></td>
<td><inputtype="file"name="file1">
<br><br>
</td></tr>
<tr><td><inputtype="submit"value="UploadFile"></td></tr>
</form>
</table>
</body>
</html>
Afterselection,thetextfielddisplaysthefullpathtotheselectedfile.Figure8-1showsthisHTMLpageinawebbrowser.
Figure8-1.HTMLpageforuploadingafiletoaservlet
Figure8-1showstheinputfieldaftertheuserhasalreadychosenthefile.Thebrowserthenautomaticallyfillsinthetextfieldwiththecompletefilepath.
Toallowtheuploadingofmultiplefiles,includemorethanoneinputtagwithdifferentvaluesforthenameattribute.ThebrowserassociatesaBrowsebuttonwitheachofthem.
SeeAlso
Recipe8.4onusingthecom.oreilly.servletlibraryforfileuploading;Recipe8.5onhandlingasinglefileupload;Recipe8.6onhandlingmultiplefileuploads;Recipe8.5oncontrollingfilenaming;Recipe8.6onusingaJSPtohandlefileuploads;thehomepageforcom.oreilly.servlet:http://www.servlets.com/cos/index.html;theRFC1867documentonform-basedfileuploads:http://www.ietf.org/rfc/rfc1867.txt.
Recipe8.2Usingthecom.oreilly.servletLibrary
Problem
Youwanttousethecom.oreilly.servletclassesthatO'ReillyauthorJasonHunterhasdevelopedtohandlefileuploads.
Ofcourse,thisisn'tmuchofaproblem,asJason'slibrarytakesmostoftheworkoutofuploadingandacceptingfiles.IuseJason'slibraryhere(withhispermission,ofcourse)becauseithandlesfileuploadsnicely,andthere'snogoodreasontoreinventaperfectlygoodwheel.
Solution
DownloadthedistributionZIPfilefromhttp://www.servlets.com/cos/index.html.Addthecos.jarfile,whichispartofthedistributiontotheWEB-INF/libdirectoryofyourwebapplication.Makesurethatyouadheretothesoftwarelicensewhenusingthelibrary.
Discussion
AJARfilenamedcos.jarincludesthecom.oreilly.servletandcom.oreilly.servlet.multipartpackages.Thesepackagesincludeseveralclasses,suchasalloftheJavaclassesthatbeginwith"Multipart,"whichcanbeusedtohandlefileuploadinginaservlet.
Thecos.jararchivealsocontainsmanyotherinterestingandusefulclassestouse
withservlets,butthefollowingrecipesfocusonfileuploads.
DownloadthelatestZIPfilecontainingthedistributionfromhttp://www.servlets.com/cos/index.html.ThecontentsoftheZIPfileincludecos.jar,whichyouneedtoaddtotheWEB-INF/libdirectoryofyourwebapplication.Inyourservlet,youthenimporttheclassesthatyouwanttouse:
importcom.oreilly.servlet.MultipartRequest;
importcom.oreilly.servlet.multipart.FileRenamePolicy;
Beforeyouhaveintegratedtheseclassesintoyourcode,makesurethatyouhavereadtheaccompanyingsoftwarelicenseforthiscode:http://www.servlets.com/cos/license.html.
Therestoftherecipesinthischapterassumethatyouhavecos.jarandtheclassesitcontainsavailableinyourwebapplication.Ifyoudon'ttakestepstomaketheseclassesavailable,noneoftheexamplesinthischapterwillfunctionproperly.
SeeAlso
Recipe8.1onpreparingtheHTMLforafileupload;Recipe8.5onhandlingasinglefileupload;Recipe8.6onhandlingmultiplefileuploadsinaservlet;Recipe8.5oncontrollingfilenaming;Recipe8.6onusingaJSPtohandlefileuploads;thehomepageforcom.oreilly.servlet:http://www.servlets.com/cos/index.html;theRFC1867documentonform-basedfileuploads:http://www.ietf.org/rfc/rfc1867.txt.
Recipe8.3UploadingOneFileataTime
Problem
Youwanttocreateacomponentthatcanreceiveaclientfileuploadandstorethefileinalocaldirectory.
Solution
Createaservletthatusesthecom.oreilly.servlet.MultipartRequestclassfromJasonHunter'scos.jararchive.
Discussion
TheMultipartRequestclassincludesseveraloverloadedconstructors.TheoneusedinExample8-3takesthejavax.servlet.http.HttpServletRequestobject,thepathtothedirectorywhereyouwanttosaveuploadedfiles,andthesizelimitforthefileasparameters.InExample8-3,iftheclientuploadsafilethatexceeds5MB,thentheUploadServletthrowsajava.io.IOException.Youcanallowthisexceptiontobemanagedbyanerror-pageelementinweb.xmlforIOExceptions,asExample8-3does,oruseatry/catchblockintheuploadservlettodealwitherrors.
SeeChapter9forhowtodeclareerrorpagesforthewebapplication.
WithMultipartRequest,assoonasthecodeinstantiatestheobject,theobjectishandlingthefileupload;inotherwords,youdonothavetocallamethodtocommencemanagingtheupload.
TheservletinExample8-3initiatesthefileuploadandthendisplaysthenameoftheuploadedfile(s).
Example8-3.AservletthatusestheMultipartRequestclass
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
importcom.oreilly.servlet.MultipartRequest;
importjava.util.Enumeration;
publicclassUploadServletextendsHttpServlet{
privateStringwebTempPath;
publicvoidinit()
webTempPath=getServletContext().getRealPath("/")+"data";
}
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//filelimitsizeof5MB
MultipartRequestmpr=newMultipartRequest(
request,webTempPath,5*1024*1024);
Enumerationenum=mpr.getFileNames();
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Servletupload</title>");
out.println("</head>");
out.println("<body>");
for(inti=1;enum.hasMoreElements();i++)
out.println("Thenameofuploadedfile"+i+
"is:"+mpr.getFilesystemName((String)enum.nextElement())
+"<br><br>");
out.println("</body>");
out.println("</html>");
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
thrownewServletException("GETmethodusedwith"+
getClass().getName()+":POSTmethodrequired.");
}
}
Thecodegeneratesthepathtothesavedirectorybycallingjavax.servlet.ServletContext.getRealPath("/")togetanabsolutepathnametotherootofthewebapplication(asinh:\home\).Thenthecodeaddsthenameofthedirectorywherethefilewillbesaved(data).
Thisdirectorynamecouldalsobeaddedusinganexternalconfigurationsuchasacontext-paramelementinweb.xml.SeeRecipe8.6fordetails.
ThemethodMultipartRequest.getFilesystemName(StringName)returnsthefilenamefromtheclient'sfilesystem.Thefilecanbesavedontheserverendwithitsoriginalfilename,oryoucanuseadifferentMultipartRequestconstructorthattakesasaparameteraFileRenamePolicyobject.Thisconstructorlookslike:
MultipartRequest(javax.servlet.http.HttpServletRequestrequest,
java.lang.StringsaveDirectory,intmaxPostSize,
FileRenamePolicypolicy)
ThereareafewversionsoftheMultipartRequestconstructorwiththeFileRenamePolicyparameter,whichisusedtorenameuploadedfiles(seeRecipe8.5).Example8-3alsothrowsaServletExceptioniftheUploadServletisrequestedwithaGETmethod,whichisnotallowedwithfileuploads.
SeeAlso
Recipe8.1onpreparingtheHTMLforafileupload;Recipe8.4ondownloadingandusingthecom.oreilly.servletlibrary;Recipe8.6onhandlingmultiplefileuploadsinaservlet;Recipe8.5oncontrollingfilenamingduringfileuploads;Recipe8.6onusingaJSPtohandlefileuploads;thehomepageforcom.oreilly.servlet:http://www.servlets.com/cos/index.html;theRFC1867documentonform-basedfileuploads:http://www.ietf.org/rfc/rfc1867.txt.
Recipe8.4UploadingMultipleFiles
Problem
Youwanttouploadmorethanonefileatatimefromaclient,andhandleeachfileasitisuploaded.
Solution
UsetheMultipartParserfromJasonHunter'scos.jararchive.
Discussion
TheMultipartParserclassallowstheservlettohandleeachfilepartsequentiallyastheserverreceivesamultipartHTTPrequest.
YoucanalsousetheMultipartRequestclasstohandlemultiplefiles.However,theMultipartParserallowsyoutohandleeachpart(suchasbysavingittoadatabase)duringtheparsingofamultiple-fileupload.
Inaddition,thefile'scontenttype,size,andnamecanbereadastheservlethandlestherequest.Theservletcanalsomakebasicchecksusingthisclass,suchascountinghowmanyfileswereuploadedandverifyingwhethertheuseruploadedafileforeachoftheavailableforminputfields.
TheHTMLfilefromRecipe8.5hasbeenalteredtoallowtheuploadofthreedifferentfilesfromtheuser'sfilesystem,asshowninFigure8-2.
Figure8-2.AnHTMLformforuploadingthreefiles
ThisHTMLformiscreatedbyincludingthreeinputtagswithtype="file",asin:
<inputtype="file"name="file1"><br><br>
<inputtype="file"name="file2"><br><br>
<inputtype="file"name="file3">
Example8-4handlesthemultiplefileuploadsbyimportingthreeclassesfromthecos.jararchive.TheMultipartParserclassrestrictsthesizeoffileuploadsto5MBinExample8-4;however,youcansetthisconstructorparametertoanothervaluetoallowsmallerorlargerfilesizes,orleavetheacceptedfilesizeatthe1MBdefault.
YoucanviewtheJavadocforthisclassathttp://www.servlets.com/cos/javadoc/com/oreilly/servlet/multipart/MultipartParser.html.
TheMultipartParserobjectthrowsajava.io.IOExceptionifanyofthefileuploadsexceedthesizelimit.Callingthe
MultipartParser.readNextPart()methodreturnsaParttype,ornulliftheincomingstreamdoesnotcontainanymoreparts.APartcanbeeitheraFilePartoraParamPart,dependingonthecontentitincludes.TheParamPartcoverstheotherparametersthatanHTMLformmightinclude,suchas"username".TheFileParthasseveralmethodsthatprovideinformationabouttheuploadedfile,suchasitscontenttypeandthefilename.TheFilePart.writeTo(java.io.Filedir)methodsavesthefiletothespecifieddirectoryandreturnsthefilesizeasalongtype.TheFilePartcanalsowritetoanOutputStream,asinwriteTo(java.io.OutputStreamout).
Example8-4.Aservlethandlingmultiplefileuploads
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
importcom.oreilly.servlet.multipart.MultipartParser;
importcom.oreilly.servlet.multipart.Part;
importcom.oreilly.servlet.multipart.FilePart;
publicclassParserServletextendsHttpServlet{
privateStringfileSavePath;
publicvoidinit(){
//saveuploadedfilestoa'data'directoryinthewebapp
fileSavePath=getServletContext().getRealPath("/")+"data";
}
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Fileuploads</title>");
out.println("</head>");
out.println("<body>");
out.println("<h2>Hereisinformationaboutanyuploadedfiles</h2>");
try{
//filelimitsizeof5MB
MultipartParserparser=newMultipartParser(
request,5*1024*1024);
Part_part=null;
while((_part=parser.readNextPart())!=null){
if(_part.isFile()){
//getsomeinfoaboutthefile
FilePartfPart=(FilePart)_part;
Stringname=fPart.getFileName();
if(name!=null){
longfileSize=fPart.writeTo(
newjava.io.File(fileSavePath));
out.println("Theuser'sfilepathforthefile:"+
fPart.getFilePath()+"<br>");
out.println("Thecontenttypeofthefile:"+
fPart.getContentType()+"<br>");
out.println("Thefilesize:"+fileSize+"bytes<br><br>");
//commencewithanotherfile,ifthereisone
}else{
out.println(
"Theuserdidnotuploadafileforthispart.");
}
}elseif(_part.isParam()){
//dosomethingelseifitisanon-file-typeparameter,
//suchasausername
}
}//endwhile
out.println("</body>");
out.println("</html>");
}catch(java.io.IOExceptionioe){
//anerror-pageinthedeploymentdescriptoris
//mappedtothejava.io.IOException
thrownewjava.io.IOException(
"IOExceptionoccurredin:"+getClass().getName());
}
}//doPost
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
thrownewServletException(
"GETmethodusedwith"+getClass().getName()+
":POSTmethodrequired.");
}
}
Figure8-3showsthedescriptivepagethattheservletdisplaysabouteachuploadedfile.
Figure8-3.Aservletdisplaysinformationaboutuploadedfiles
SeeAlso
Recipe8.1onpreparingtheHTMLforafileupload;Recipe8.4ondownloadingandusingthecom.oreilly.servletlibrary;Recipe8.5onhandlingasinglefileuploadinaservlet;Recipe8.5oncontrollingfilenaming;Recipe8.6onusingaJSPtohandlefileuploads;thehomepageforcom.oreilly.servlet:http://www.servlets.com/cos/index.html;theRFC1867documentonform-basedfileuploads:http://www.ietf.org/rfc/rfc1867.txt.
Recipe8.5RenamingFiles
Problem
Youwanttorenametheuploadedfilesaccordingtoastandardpolicyortoavoidconflictswithexistingfilesthathavethesamename.
Solution
Createaclassthatimplementsthecom.oreilly.servlet.multipart.FileRenamePolicyinterface,orusetheDefaultFileRenamePolicyclass.Thenusethatclassasaparameterintheconstructorforthecom.oreilly.servlet.MultipartRequestclass.
Discussion
Thecom.oreilly.servlet.multipartpackagecontainsaFileRenamePolicyinterfacethatcanbeusedwhenyouwanttoimplementaparticularfile-renamingpolicywithfileuploads.
TheDefaultFileRenamePolicyclassrenamesanuploadedfilewhosenameconflictswithanexistingfilebyaddinganumbertotheuploadedfilename.Forexample,ifindex.txtalreadyexists,thentheDefaultFileRenamePolicyclassrenamestheuploadedfileindex1.txt;andifasecondfileisuploadedwiththesamenameitwillberenamedindex2.txt,andsoon.
Ifyouwanttoimplementyourownrenamingpolicy,thencreateyourownclassthatimplementstheFileRenamePolicyinterface,then
implementtheclass'srename(java.io.Filefile)methodtoinitiatetherenamingaction.
ThiscodesampleshowsaMultipartRequestconstructorfromExample8-3.Thistime,theconstructoraddsaDefaultFileRenamePolicyobjectasaconstructorparameter:
MultipartRequestmpr=newMultipartRequest(
request,webTempPath,(5*1024*1024),newDefaultFileRenamePolicy());
Makesuretoincludethefollowingimportstatementsintheservletclass:
importcom.oreilly.servlet.MultipartRequest;
importcom.oreilly.servlet.multipart.DefaultFileRenamePolicy;
Asmentionedbefore,youcanimplementtheFileRenamePolicyinterfaceyourselfandcreateacustomfile-renamingmechanism.Example8-5showsaMyFileRenamePolicyclassthatrenameseachuploadedfilebyappendingatimestamptotheendofitsname.Thesimpletimestampiscalculatedas:
//secondssinceJan1,1970,00:00:00
newjava.util.Date().getTime()/1000
ThecoderenamesthefilebyappendingtheString(representingaseriesofnumbers)tothefilenameminusitsextension,andthenappendingtheextensionattheend(ifthefilenameoriginallyhadanextension).
Example8-5.RenaminguploadedfileswithyourownJavaclass
packagecom.jspservletcookbook;
importjava.io.File;
importjava.util.Date;
importcom.oreilly.servlet.multipart.FileRenamePolicy;
publicclassMyFileRenamePolicyimplementsFileRenamePolicy{
//implementtherename(Filef)methodtosatisfythe
//FileRenamePolicyinterfacecontract
publicFilerename(Filef){
//Gettheparentdirectorypathasinh:/home/useror/home/user
StringparentDir=f.getParent();
//Getfilenamewithoutitspathlocation,suchas'index.txt'
Stringfname=f.getName();
//Gettheextensionifthefilehasone
StringfileExt="";
inti=-1;
if((i=fname.indexOf("."))!=-1){
fileExt=fname.substring(i);
fname=fname.substring(0,i);
}
//addthetimestamp
fname=fname+(""+(newDate().getTime()/1000));
//piecetogetherthefilename
fname=parentDir+System.getProperty(
"file.separator")+fname+fileExt;
Filetemp=newFile(fname);
returntemp;
}
}
Giventhatyournewclassiscalledcom.jspservletcookbook.MyFileRenamePolicyandimplementstheFileRenamePolicyinterface,theconstructorfortheMultipartRequestwouldnowlooklikethis:
MultipartRequestmpr=newMultipartRequest(
request,webTempPath,(5*1024*1024),
newcom.jspservletcookbook.MyFileRenamePolicy());
StoreyournewclassintheWEB-INF/classesdirectoryofthewebapplicationusingthesamedirectorystructureastheclass'spackagename(asinWEB-INF/classes/com/jspservletcookbook/MyFileRenamePolicy.class).
Ingeneral,thecom.oreilly.servletpackagealsoincludestheMultipartFilterclass.AccordingtoanarticlethatJasonhaswritten(http://www.servlets.com/soapbox/filters.html),"TheMultipartFilterworksbywatchingincomingrequestsandwhenitdetectsafileuploadrequest(withthecontenttypemultipart/form-data),thefilterwrapstherequestobjectwithaspecialrequestwrapperthatknowshowtoparsethespecialcontenttypeformat."
SeeAlso
Recipe8.1onpreparingHTMLforafileupload;Recipe8.4ondownloadingandusingthecom.oreilly.servletlibrary;Recipe8.3andRecipe8.6onhandlingsingle-andmultiple-fileuploadsinaservlet;Recipe8.6onusingaJSPtohandlefileuploads;thehomepageforcom.oreilly.servlet:http://www.servlets.com/cos/index.html;theRFC1867documentonform-basedfileuploads:http://www.ietf.org/rfc/rfc1867.txt.
Recipe8.6UsingaJSPtoHandleaFileUpload
Problem
YouwanttouseaJSPtohandleafileupload.
Solution
CreateaJavaBeanthatwrapsthefunctionalityofthecom.oreilly.servlet.MultipartRequestclassfromJasonHunter'scos.jarlibrary.Thenusethejsp:useBeanstandardactioninaJSPtocreateaninstanceofthisbeanforhandlingthefileuploads.
Discussion
ThisrecipedescribesaJavaBeanthatusesthecom.oreilly.servlet.MultipartRequestclasstomanagefileuploads.First,I'llshowthebeanthatwrapsthefunctionalityoftheMultipartRequestclass,thentheJSPthatusesthebeantouploadafile.
Example8-6showstheUploadBeanusedbytheJSPinExample8-7.
Example8-6.Afile-uploadingJavaBean
packagecom.jspservletcookbook;
importjava.util.Enumeration;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.ServletRequest;
importcom.oreilly.servlet.MultipartRequest;
importcom.oreilly.servlet.multipart.DefaultFileRenamePolicy;
publicclassUploadBean{
privateStringwebTempPath;
privateHttpServletRequestreq;
privateStringdir;
publicUploadBean(){}
publicvoidsetDir(StringdirName){
if(dirName==null||dirName.equals(""))
thrownewIllegalArgumentException(
"invalidvaluepassedto"+getClass().getName()+".setDir");
webTempPath=dirName;
}
publicvoidsetReq(ServletRequestrequest){
if(request!=null&&requestinstanceofHttpServletRequest){
req=(HttpServletRequest)request;
}else{
thrownewIllegalArgumentException(
"Invalidvaluepassedto"+getClass().getName()+".setReq");
}
}
publicStringgetUploadedFiles()throwsjava.io.IOException{
//filelimitsizeof5MB
MultipartRequestmpr=newMultipartRequest(
req,webTempPath,5*1024*1024,newDefaultFileRenamePolicy());
Enumerationenum=mpr.getFileNames();
StringBufferbuff=newStringBuffer("");
for(inti=1;enum.hasMoreElements();i++){
buff.append("Thenameofuploadedfile").append(i).
append("is:").
append(mpr.getFilesystemName((String)enum.nextElement())).
append("<br><br>");
}//for
//returntheString
returnbuff.toString();
}//getUploadedFiles
}
ThiscodeimportstheclassesitneedstohandletheuploadedfileswiththeMultipartRequestclass.TheDefaultFileRenamePolicyclassisusedintheMultipartRequestconstructortohandleconflictsbetweenthenamesofuploadedfilesandanyexistingfileswiththesamename.Whenthesenamingconflictsoccur,theDefaultFileRenamePolicyclassautomaticallyaddsanumbertotheendoftheuploadedfile,asinindex1.txtiftheuploadedfilewasnamedindex.txt.
Example8-6usestheJavaBeannamingconventionsforitsmethods,asinsetDir()andgetUploadedFiles(),whichallowthemethods
tobecalledusingthejsp:getPropertyandjsp:setPropertystandardactions.Example8-7showstheuseofbothoftheseactionsandtheJSPthathandlesthefileuploadanddisplayinformationabouttheuploadedfiles.
TheJSPusestheUploadBean,theclassIjustdefined.TheJSPinstantiatesthebeanusingthejsp:useBeanstandardaction,setsthedirectorynamewheretheuploadedfilewillbesavedwithjsp:setProperty,thenusesjsp:getPropertytosavethefile(s)tothespecifieddirectory.
Example8-7.AJSPthatuploadsfilesanddisplaysinformationaboutthem
<jsp:useBeanid="uploader"class="com.jspservletcookbook.UploadBean"/>
<jsp:setPropertyname="uploader"property="dir"
value="<%=application.getInitParameter(\"save-dir\")%>"/>
<jsp:setPropertyname="uploader"property="req"value="<%=request%>"/>
<html>
<head><title>fileuploads</title></head>
<body>
<h2>Hereisinformationabouttheuploadedfiles</h2>
<jsp:getPropertyname="uploader"property="uploadedFiles"/>
</body>
</html>
TheJSPinExample8-7createsaninstanceoftheUploadBeanwiththiscode:
<jsp:useBeanid="uploader"class="com.jspservletcookbook.UploadBean"/>
Thecom.jspservletcookbook.UploadBeanclassmustbeplacedinthewebapplication'sWEB-INF/classesdirectory(insideofWEB-INF/classes/com/jspservlet/cookbook),orinaJARfileinsideofWEB-INF/lib.
TheJSPthenpassestheHttpServletRequestobjecttothebeanwiththiscode:
<jsp:setPropertyname="uploader"property="req"value="<%=request%>"/>
UnderJSP2.0,youcanpassalongtherequestvaluewiththiscode:
<jsp:setPropertyname="uploader"property="req"value="${pageContext.request}"/>
TheJSP2.0specificationallowstheuseofELsyntaxinthejsp:setPropertyvalueattribute.
ThebeanneedstherequestobjecttopassintotheMultipartRequestconstructor,whichdoesallthefile-uploadingwork.TheJSPalsospecifiesthedirectorywhereuploadedfilesaresaved:
<jsp:setPropertyname="uploader"property="dir"
value="<%=application.getInitParameter(\"save-dir\")%>"/>
Theexpressionapplication.getInitParameter(\"save-dir\")returnsthevalueofthecontextparametersave-dir,whichisthepathtothedirectorywheretheuploadedfilesaresaved.Hereiswhatthisweb.xmlelementlookslike:
<!--beginningofdeploymentdescriptor-->
<context-param>
<param-name>save-dir</param-name>
<param-value>h:\home\data</param-value>
</context-param>
<!--deploymentdescriptorcontinues-->
Thefinalstepistocallthebean'sgetUploadedFiles()method.TheJSPaccomplishesthistaskusingthejsp:getPropertystandardaction,asin:
<jsp:getPropertyname="uploader"property="uploadedFiles"/>
TheJSPcancallthebean'smethodinthismanner,asthoughtheJSPwasfetchingabeanproperty,becauseInamedthemethodwiththestandard"get"prefix:getUploadedFiles().Tricky!
Figure8-4showstheresultingwebpageaftertheuserhassubmittedtheHTMLform.
Figure8-4.AJSPthathandlesfileuploads
TousethisJSPtohandleafileupload,youhavetospecifyitinanHTMLformtag'sactionattribute,asin:
<formaction="http://localhost:9000/home/upload.jsp"method="post"
enctype="multipart/form-data">
SeeAlso
Recipe8.1onpreparingtheHTMLforafileupload;Recipe8.4ondownloadingandusingthecom.oreilly.servletlibrary;Recipe8.3andRecipe8.6onhandlingsingle-andmultiple-fileuploadsinaservlet;Recipe8.5oncontrollingfilerenamingasfilesareuploaded;thehomepageforcom.oreilly.servlet:http://www.servlets.com/cos/index.html;theRFC1867documentonform-basedfileuploads:http://www.ietf.org/rfc/rfc1867.txt.
Chapter9.HandlingExceptionsinWebApplications
Introduction
Recipe9.1.DeclaringExceptionHandlersinweb.xml
Recipe9.2.CreatinganException-HandlingServlet
Recipe9.3.SendinganErrorfromaServlet
Recipe9.4.SendinganErrorfromaJSP
Recipe9.5.CreatinganError-HandlingJSP
Recipe9.6.DeclaringaSpecialException-HandlingJSPforOtherJSPs
Introduction
Webapplicationscansometimesshowanumberoferrorsthatyoudon'twantuserstosee.Ifauserwhoexpectstobeservedaninformation-richpageisinsteadgreetedwithanuglyandincomprehensibleannouncementofan"HTTPStatus500"inherwebbrowser,youcanbetthisvisittothesitewillbeherlast!AllwebsiteshandleunexpectedHTTPstatuscodes(suchasthe"404NotFound"or"403Forbidden")withafriendlyandinformativeerrormessage,butyou'llwanttohidethesemessagesfromyourusers.ToolstohandlebothJavaruntimeexceptionsandtheseunanticipatedHTTPstatuscodesareavailabletodevelopers,andtherecipesinthischaptershowyouhowtousethemeffectively.
Recipe9.1DeclaringExceptionHandlersinweb.xml
Problem
YouwanttodisplaycertainservletsorJSPswhenawebcomponentthrowsaJavaexceptionorgeneratesunexpectedserverresponsecodes.
Solution
Usetheerror-pageelementinweb.xmltospecifytheinvocationofservletsorJSPsinresponsetocertainexceptionsorHTTPstatuscodes.
Discussion
AJavawebdevelopershouldhandlethesetypesofunexpectedoccurrenceswithinhiswebapplication:
The"404NotFound"serverresponsecode,whichindicatesthattheuserhasmadeamistakewhentypingintheURL,orrequestedapagethatnolongerexists.
The"500InternalServerError"thatcanberaisedbyaservletwhenitcallssendError(500)ontheHttpServletResponseobject.
Runtimeexceptionsthatarethrownbythewebapplicationandnotcaughtbythefilter,servlet,orJSP.
Youconfigurethehandlingofexceptionsandserverresponsecodeswiththeerror-pageelementinthedeploymentdescriptor.Theerror-pageelementinweb.xmlcomesafteranyservlet,servlet-mapping,session-config,mime-mapping,andwelcome-file-listelements,aswellasbeforeanytaglib,resource-env-ref,resource-ref,orsecurity-constraintelements.Theerror-pageelementincludesamappingbetweenthestatuscodeorexceptiontype,aswellasthepathtoawebresource.Thisresource,whichshouldbeaservlet,JSP,orHTMLfile,shouldinformtheuseraboutwhathappenedandprovidelinkstootherpartsofthewebsite,dependingonthenatureoftheerror.
Example9-1showsadeploymentdescriptorforservletAPI2.3thatconfigureserrorpages.
Example9-1.Configuringerrorpagesinweb.xml
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<!--topofdeploymentdescriptor,suchasfilter,servlet,servlet-mapping,session-
config,welcome-fileelements-->
<servlet>
<servlet-name>Error404</servlet-name>
<servlet-class>com.jspservletcookbook.Error404</servlet-class>
</servlet>
<servlet>
<servlet-name>Error403</servlet-name>
<servlet-class>com.jspservletcookbook.Error403</servlet-class>
</servlet>
<servlet>
<servlet-name>ErrorIo</servlet-name>
<servlet-class>com.jspservletcookbook.ErrorIo</servlet-class>
</servlet>
<servlet>
<servlet-name>ErrorServlet</servlet-name>
<servlet-class>com.jspservletcookbook.ErrorServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>ErrorGen</servlet-name>
<servlet-class>com.jspservletcookbook.ErrorGen</servlet-class>
</servlet>
<!--servletmappings-->
<servlet-mapping>
<servlet-name>Error404</servlet-name>
<url-pattern>/err404</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Error403</servlet-name>
<url-pattern>/err403</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ErrorIo</servlet-name>
<url-pattern>/errIo</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ErrorServlet</servlet-name>
<url-pattern>/errServ</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ErrorGen</servlet-name>
<url-pattern>/errGen</url-pattern>
</servlet-mapping>
<!--error-coderelatederrorpages-->
<!--NotFound-->
<error-page>
<error-code>404</error-code>
<location>/err404</location>
</error-page>
<!--Forbidden-->
<error-page>
<error-code>403</error-code>
<location>/err403</location>
</error-page>
<!--exception-typerelatederrorpages-->
<error-page>
<exception-type>javax.servlet.ServletException</exception-type>
<location>/errServ</location>
</error-page>
<error-page>
<exception-type>java.io.IOException</exception-type>
<location>/errIo</location>
</error-page>
<!--allothertypes-->
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/errGen</location>
</error-page>
<!--web.xmlcontinues;tag-lib,resource-ref,security-constraintelements,etc.-->
</web-app>
Whenaservletthrowsanexception,thewebcontainersearchestheconfigurationsinweb.xmlthatusetheexception-typeelementforamatchwiththethrownexceptiontype.InExample9-1,ifthewebapplicationthrowsaServletException,thenthewebcontainerinvokesthe/errServservlet.Thewebcontainerinvokestheclosestmatchintheclasshierarchy.Forexample,ifaservletthrowsanIOException,thecontainerinvokesthe/errIoservletthatismappedtothethrownexceptiontype,notthecomponentmappedtojava.lang.ThrowableeventhoughIOExceptionisinthesameclasshierarchyasThrowable.IfthisapplicationthrowsanIllegalStateException,thecontainerinvokesthe/errGenservlet(whichismappedtoThrowable),becausethereisnospecificerrorpagemappingforIllegalStateException.
IntheeventofanHTTPresponsecodeof403or404,thecontainerinvokesthewebcomponentsorHTMLpagesmappedwiththelocationelementtothoseexactnumbers.
Thewebcontainermustreturnaresponsecodeof500ifanexceptionoccursthatisnothandledbythiserror-pagemechanism,accordingtotheservletAPIspecification.
SeeAlso
Recipe9.2oncreatingaservleterrorhandler;Recipe9.3onsendinganerrorfromaservlet;Recipe9.4onsendinganerrorfromaJSP;Recipe9.5onusingJSPstohandleerrors;Recipe9.6ondeclaringinaJSPthatanotherJSPwillhandleitsexceptions;Chapter1onthedeployment
descriptor;theJavaservletspecification,whichcoverserrorhandlinginChapterSRV.9.9:http://java.sun.com/products/servlet/index.html.
Recipe9.2CreatinganException-HandlingServlet
Problem
Youwanttocreateaservletthatgeneratesanerrorpage.
Solution
Createaservletthatdisplayssomeinformationabouttheerror,thenmapexceptiontypesand/orerrorcodestotheservletinthedeploymentdescriptor.
Discussion
Anerror-handlingservlethasaccesstoseveralrequestattributesthatitcanusetodescribetheerror.Theerrorpagealsohasaccesstotherequestandresponseobjectsassociatedwiththepagethatgeneratedtheerror.Forexample,thejava.lang.Throwableobjectassociatedwithanyexceptionscanbeaccessedwiththefollowingcode:
Throwablethrowable=(Throwable)
request.getAttribute("javax.servlet.error.exception");
Youcanaccesstheserverresponsecodewiththiscode:
Stringstatus_code=((Integer)
request.getAttribute("javax.servlet.error.status_code")).toString();
Table9-1showstherequestattributesthatanerror-handlingservlethas
accessto.
Table9-1.Requestattributesavailabletoservleterrorpages
Requestattribute Javatype
javax.servlet.error.status_code java.lang.Integer
javax.servlet.error.exception_type java.lang.Class
javax.servlet.error.message java.lang.String
javax.servlet.error.exception java.lang.Throwable
javax.servlet.error.request_uri java.lang.String
javax.servlet.error.servlet_name java.lang.String
Example9-2showstheErrorGenservlet.ThewebcontainerinvokesthisservletwhenanotherservletorJSPthrowsanunhandledThrowable,accordingtotheconfigurationinExample9-1.
Example9-2.Anerror-handlingservlet
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassErrorGenextendsHttpServlet{
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//checktheservletexception
Throwablethrowable=(Throwable)
request.getAttribute("javax.servlet.error.exception");
StringservletName=(String)
request.getAttribute("javax.servlet.error.servlet_name");
if(servletName==null)
servletName="Unknown";
StringrequestUri=(String)
request.getAttribute("javax.servlet.error.request_uri");
if(requestUri==null)
requestUri="Unknown";
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Errorpage</title>");
out.println("</head>");
out.println("<body>");
if(throwable==null){
out.println("<h2>Theerrorinformationisnotavailable</h2>");
out.println("Pleasereturntothe<ahref=\""+
response.encodeURL("http://localhost:8080/home")+
"\">homepage</a>.");
}else{
out.println("<h2>Hereistheerrorinformation</h2>");
out.println(
"Theservletnameassociatedwiththrowingtheexception:"+
servletName+"<br><br>");
out.println("Thetypeofexception:"+
throwable.getClass().getName()+"<br><br>");
out.println("TherequestURI:"+requestUri+"<br><br>");
out.println("Theexceptionmessage:"+throwable.getMessage());
}
out.println("</body>");
out.println("</html>");
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
doPost(request,response);
}
}
Theservletgetsareferencetothethrownexception,thendisplaysinformationsuchastheexception'sclassnameandtheexceptionmessage.TherequestURIrepresentsapartialpath(suchas/home/errGen.jsp)tothecomponentthatthrewtheexception,whichcanbeveryhelpfulfordebuggingandinformationpurposes.Figure9-1showswhatthebrowserdisplayswhenaservletthrowsanexceptionusingTomcat'swebcontainer.
Figure9-1.ErrorpageHTMLdisplayedbyanerror-handlingservlet
Figure9-2showstheerrorpagedisplayedbyourexampleservletwhenaJSPinthesamewebapplicationthrowsajava.lang.ArithmeticException.
Figure9-2.TheerrorpagedisplayedbyExample9-1whenaJSPthrowsanexception
SeeAlso
Recipe9.1ondeclaringexceptionhandlersinthedeploymentdescriptor;Recipe9.3onsendinganerrorfromaservlet;Recipe9.4onsendinganerrorfromaJSP;Recipe9.5onusingJSPstohandleerrors;Recipe9.6ondeclaringinaJSPthatanotherJSPwillhandleitsexceptions;Chapter1onthedeploymentdescriptor;theJavaservletspecification,whichcoverserrorhandlinginChapterSRV.9.9:http://java.sun.com/products/servlet/index.html.
Recipe9.3SendinganErrorfromaServlet
Problem
Youwanttouseaservlettomanuallysendaresponseerrortotheclient.
Solution
Usethejavax.servlet.HttpServletResponse.sendError()method.
Discussion
Thejavax.servlet.http.HttpServletResponseclasshastwoversionsofthesendError()method:onethattakesanintparameterrepresentingtheHTTPresponsecode(suchas500),andtheothertakinganintparameterandaStringerrormessage.TheStringparameterisusedtodisplayamessagetotheclientifanerrorpageisnotconfiguredforthatparticularresponsecode.Example9-3showstheskeletonofaservletwhosecommentedsectionsdescribevariousscenariosforsendingresponsecodes.
Usethetwo-parametermethodversion,sothatameaningfulmessageisdisplayedintheeventthattheapplicationhasnotconfiguredanerrorpageforaparticularerrorcode.
Example9-3.Sendingaresponsecodefromaservlet
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSenderextendsHttpServlet{
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
/*iftheservlettriestoaccessaresourceandfindsoutthattheclientisnot
authorizedtoaccessit-"401Unauthorized"*/
//response.sendError(401,
//"Youarenotauthorizedtoviewtherequestedcomponent");
/*iftheservlettriestoaccessaresourcethatisforbiddenforthisclientandthere
isnofurtherinformationonit-"403Forbidden"*/
//response.sendError(403,
//"Youareforbiddenfromviewingtherequestedcomponent;no
//furtherinformation");
/*iftheservlettriestoaccessaresourcethatisnotfoundgiventheclient'sprovided
URL-"404NotFound"*/
//response.sendError(404,
//"Theservercouldnotfindtherequestedcomponent");
}
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
doPost(request,response);
}
}
IfanerrorpageisconfiguredfortheerrorcodethatyouspecifiedinthesendError()method,thewebcontainerinvokestheerrorpagemappedtothaterrorcode.Iftheerrorcodedoesnothaveanerrorpageconfiguredforitinweb.xml,thewebcontainergeneratesadefaultHTMLpagecontainingthemessageyouincludedastheStringparametertothesendError()method,asinFigure9-3.TheserverleavescookiesandotherresponseheadersunmodifiedwhenitreturnsthisHTMLtotheclient.
IfyoucallsendError()afteralreadycommittingtheresponsetotheclient(suchaswhentheresponsebuffer,atemporarystoragelocationfortheresponsedata,isfulland"auto-flushed"),sendError()throwsajava.lang.IllegalStateException.Youcansetthebuffersizewiththejavax.servlet.ServletResponse.setBufferSize()method.
Figure9-3.ServerresponsetoHttpServletResponse.sendErrorwhenthereisnoerror
pageisconfiguredfortheerrorcode
SeeAlso
Recipe9.1ondeclaringexceptionhandlersinthedeploymentdescriptor;Recipe9.2ondevelopingaservleterrorhandler;Recipe9.4onsendinganerrorfromaJSP;Recipe9.5onusingJSPstohandleerrors;Recipe9.6ondeclaringinaJSPthatanotherJSPwillhandleitsexceptions;Chapter1onthedeploymentdescriptor;theJavaservletspecification,whichcoverserrorhandlinginChapterSRV.9.9:http://java.sun.com/products/servlet/index.html.
Recipe9.4SendinganErrorfromaJSP
Problem
YouwanttouseaJSPtomanuallysendaresponseerrortoaclient.
Solution
UsetheresponseimplicitobjectandthesendErrormethodinsideaJSPscriptlet.
Discussion
IfyouwanttosendaresponseerrorfromaJSP,thensimplygrabtheresponseimplicitobjectinsideascriptletandcallsendError()onit.MakesurenottocallsendError()afteralreadyflushingorcommittingtheresponsetotheclient,orthemethodwillthrowajava.lang.IllegalStateException.TheJSPcodeinExample9-4,whichcouldbeastandaloneJSPorafragmentofalargerpage,resultsinthedisplayofFigure9-3whenrequestedwiththefollowingquerystring:"?client-unauthorized=true".
Example9-4.UsingtheresponseimplicitobjecttosendaresponseerrorfromaJSP
<%@tagliburi=
"http://java.sun.com/jstl/core"prefix="c"%>
<c:iftest="${param.client-unauthorized}">
<%response.sendError(401,
"Youarenotauthorizedtoviewtherequestedcomponent");
%>
</c:if>
SeeAlso
Recipe9.1ondeclaringexceptionhandlersinthedeploymentdescriptor;Recipe9.2ondevelopingaservleterrorhandler;Recipe9.3onsendinganerrorfromaservlet;Recipe9.5onusingJSPstohandleerrors;Recipe9.6ondeclaringinaJSPthatanotherJSPwillhandleitsexceptions;Chapter1onthedeploymentdescriptor;theJavaservletspecification,whichcoverserrorhandlinginChapterSRV.9.9:http://java.sun.com/products/servlet/index.html.
Recipe9.5CreatinganError-HandlingJSP
Problem
YouwanttouseaJSPasyourerrorpageforbothservletsandJSPs.
Solution
CreateaJSPthatdisplaysinformationaboutthejava.lang.Throwablereportedbyusingthespecifiedrequestattributes,suchasjavax.servlet.error.exception.Usetheerror-pageattributeinweb.xmltomapcertainexceptiontypestotheJSP.
Discussion
AJSPcandisplayerrorinformationinthesamemannerastheservletusedinRecipe9.2.Example9-5canbeusedastheerrorpageforbothJSPsandservlets.ThissampleJSPusestheJSTLandtheELtodisplaythethrownexception'svariouscharacteristics,suchasitsfullyqualifiedclassname.
Example9-5.UsingaJSPasanerrorpage
<%@pageisErrorPage="true"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>Sorryabouttheerror</title></head>
<body>
<h2>Sorry,WeErredHandlingYourRequest</h2>
<strong>Hereisinformationabouttheerror:</strong><br><br>
Theservletnameassociatedwiththrowingtheexception:
<c:outvalue="${requestScope[\"javax.servlet.error.servlet_name\"]}"/>
<br><br>
Thetypeofexception:
<c:outvalue=
"${requestScope[\"javax.servlet.error.exception\"].class.name}"/>
<br><br>
TherequestURI:
<c:outvalue="${requestScope[\"javax.servlet.error.request_uri\"]}"/>
<br><br>
Theexceptionmessage:
<c:outvalue=
"${requestScope[\"javax.servlet.error.exception\"].message}"/>
</body>
</html>
TheerrorpagegrabstherequestUniformResourceIndicator(URI),whichistheservletpathbeginningwiththecontextpathandnotincludinganyquerystring,withthiscode:
<c:outvalue="${requestScope[\"javax.servlet.error.request_uri\"]}"/>
Thispassesthevalueofarequestattributenamedjavax.servlet.error.request_uritothec:outJSTLtag,whichresultsintheattributevaluedisplayedintheHTML.MakesuretoescapethedoublequotesinsidetheELphrase,asin:
"${requestScope[\"javax.servlet.error.request_uri\"]"
Thecodegetsinformationabouttheexceptionfromtherequestattributesthatareautomaticallycreatedbythewebcontainerwhenthe
servletorJSPthrowsanexception.Forexample,ifyouwanttoaddtheresponsestatuscodetothisinformation,thenthisnumberisavailablefromtherequestattributejavax.servlet.error.status_code.
SeeTable9-1forthecompletelistoftheseattributes.
Inaddition,thepartofExample9-5thatgetstheclassnameoftheexceptioncallsgetClass().getName()ontheThrowableobject.Figure9-4showsthebrowserdisplayofthiserrorpageafteraJSPnamederrGen.jspgeneratesanerror.
Figure9-4.AJSPerrorpagedisplaysinformationaboutathrownexception
Theweb.xmldeploymentdescriptorusesthefollowingelementtospecifythattheerrorpageofExample9-5shouldhandleany
java.io.IOExceptions:
<error-page>
<exception-type>java.io.IOException</exception-type>
<location>/errHandler.jsp</location>
</error-page>
Example9-6showstheJSPthatthrowstheexception.
Example9-6.AJSPthatthrowsajava.io.IOException
<html>
<head><title>ExceptionThrower</title></head>
<body>
<h2>ThrowanIOException</h2>
<%java.io.Filefile=newjava.io.File(
"z:"+System.getProperty("file.separator")+"temp");
file.createNewFile();%>
</body>
</html>
SeeAlso
Recipe9.1ondeclaringerrorpagesinweb.xml;Recipe9.2oncreatingaspecialexception-handlingservlet;Recipe9.3onsendinganerrorfromaservlet;Recipe9.4onsendinganerrorfromaJSP;Recipe9.6ondeclaringinaJSPthatanotherJSPwillhandleitsexceptions;Chapter23onusingtheJSTL;theJSP2.0specificationanditsChapterJSP.1.4onerrorhandling:http://java.sun.com/products/jsp/.
Recipe9.6DeclaringaSpecialException-HandlingJSPforOtherJSPs
Problem
YouwanttodeclareinsideofaJSPthatanotherorexternalJSPwillhandleanythrownerrors.
Solution
SetthepagedirectiveattributeerrorPagetothespecialJSPerrorpage'spathinthewebapplication.TheJSPerrorpageitselfhasitspagedirectiveattributeisErrorPagesetto"true".
Discussion
TheJSPspecificationallowsaJSPauthortodeclareatthetopofthepagethataspecialerror-handlingJSPwillhandleanyexceptionsthrownbythepagethattheyareauthoring.ThisdesignallowstheencapsulationoferrorhandlinginsideaspeciallydesignedJSP.
IfyouwanttospecificallytargetaJSPerrorpagewithinJSPcode,setthepagedirective'serrorPageattributetothetargeterrorpage'slocationinthewebapplication.Example9-7showsaJSPwithapagedirectivedeclaringerrHandler.jspasitserrorpage.
Thispagedirectivedeclarationoverridesanymatchingerror-pageconfigurationsinweb.xml.IfthisJSPthrowsanjava.io.IOExceptionandweb.xmlhasanexception-typeattributeforthatexception,thewebcontainerinvokestheerrorpagespecifiedbythepagedirectiveinsteadofanyURIspecifiedintheweb.xmlconfiguration.
Example9-7.AJSPthatspecifiesanotherJSPasitserrorpage
<%@pageerrorPage="/errHandler.jsp"%>
<html>
<head><title>ExceptionThrower</title></head>
<body>
<h2>ThrowanIOException</h2>
<%
java.io.Filefile=newjava.io.File("z:"+System.getProperty("file.separator")+
"temp");
file.createNewFile();%>
</body>
</html>
Theerrorpagehasaccesstoanexceptionimplicitobjectthatrepresentsthejava.lang.Throwableobjectassociatedwiththeerror.
Example9-8usestheJSTLandtheELtoshowinformationabouttheexception.SeeChapter23ifyouhavenotyetbeenintroducedtotheJSTLortheEL.
Example9-8.AJSPerrorpagenamederrHandler.jsp
<%@pageisErrorPage="true"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>Sorryabouttheerror</title></head>
<body>
<h2>Sorry,WeErredHandlingYourRequest</h2>
<strong>Hereisinformationabouttheerror:</strong><br><br>
Theservletnameassociatedwiththrowingtheexception:
<%--JSP2.0usageonly!
<c:outvalue="${pageContext.errorData.servletName}"/>--%>
<br><br>
Thetypeofexception:
<c:outvalue="${pageContext.exception.class.name}"/>
<br><br>
TherequestURI:
<%--JSP2.0usageonly!
<c:outvalue="${pageContext.errorData.requestURI}"/>--%>
<br><br>
Theexceptionmessage:
<c:outvalue="${pageContext.exception.message}"/>
</body>
</html>
Figure9-5showstheerrHandler.jsppagedisplayedinabrowser,aftertheJSPinExample9-7hasthrownajava.io.IOExceptionwhiletryingtocreateafileonaphantomdisk.Thecommented-outsectionsofExample9-8showtheuseofthejavax.servlet.jsp.ErrorDataclass,whichallowsyoutousetheELtogetmoreinformationabouttheerror.Forexample,youcangettherequestURI(asin/home/errGen.jsp)oftheoffendingJSPwiththissyntax:
${pageContext.errorData.requestURI}
However,thisusagefailsinaJSP1.2containersuchasTomcat4.1.12,becauseitwasintroducedinJSP2.0.Thisiswhythereisanemptyspaceinthebrowserpageafter"TherequestURI:."
Figure9-5.AJSPerrorpageusingthepagedirectiveattributeserrorPageandisErrorPage
Youcanalsousethissyntaxtogetaccesstothejava.lang.Throwableobjectintheerrorpage:
<c:outvalue="${requestScope[
\"javax.servlet.jsp.jspException\"]}"/>
SeeAlso
Recipe9.1ondeclaringerrorpagesinweb.xml;Recipe9.2oncreatingaspecialexception-handlingservlet;Recipe9.3onsendinganerrorfromaservlet;Recipe9.4onsendinganerrorfromaJSP;Recipe9.5onusingJSPstohandleerrors;Chapter23onusingtheJSTL;ChapterJSP.1.4oftheJSP2.0specificationonerrorhandling:http://java.sun.com/products/jsp/.
Chapter10.ReadingandSettingCookiesIntroduction
Recipe10.1.SettingaCookiewithaServlet
Recipe10.2.CreatinganArrayfromAlloftheRequest'sCookies
Recipe10.3.SettingaCookiewithaJSP
Recipe10.4.ReadingCookieValueswithaServlet
Recipe10.5.ReadingCookieValueswithaJSP
Recipe10.6.AlteringorRemovingaCookieThatHasAlreadyBeenSet
Introduction
Inatypicalvisittoawebsite,ausersendsmultiplerequestsforresourcestoawebserver.Ifawebpagecontainsmanyimages(andmostdo!),thenrequestingthesinglewebpageinvolvesoneHTTPrequestfortheHTMLcodeandothertemplatetext(suchasheadlinesandphrases),followedbyseparaterequestsforeachimagethewebpagecontains.Futurerequestsforthesamepageoftenreturnversionsofthesetextandimagesthatarecachedontheclient'scomputerforthesakeofefficiency,dependingonwhetherthefetchedresourcespermitcaching.Atanyrate,theserverviewseachHTTPrequestforthesewebresourcesasseparateanddiscretefromtheotherrequests.Withouttheuseofadditionalprotocols,theserverdoesnothaveamechanismformanagingclientstate,suchastheprogressofawebuserthroughaquestionnaireorstorefront.Beingabletologicallyrelateoneormorewebrequestsasasingleusersessioniswherecookiescomein.
Acookieisasmallpieceofinformationonauser'scomputerthatawebservercanusetoidentifythatuserthenexttimehevisitsthesite.Whenauserinitiallyvisitsthecookie-enabledsite,theserverrespondswithanextraresponseheaderthatlookslike:
Set-Cookie:mycookie=1051565332678;Domain=.myorg.com;
Expires=Tue,29-Apr-200307:42:12GMT
Consequently,whentheuservisitsthesamesite,hisbrowsersendsanextrarequestheaderthatcontainsthecookieassociatedwiththatweblocation.Hereiswhattherequestheaderslooklikewhentheclientreturnstothesitethatpreviouslysetthecookie;sincetheservletcontainerisTomcat4.1.12,theCookierequestheaderalsoincludesaname/valuepairforthesession-relatedcookie(JSESSIONID):
GET/home/cookieHTTP/1.1
Accept:image/gif,image/x-xbitmap,image/jpeg,image/pjpeg,application/msword,
application/vnd.ms-powerpoint,application/vnd.ms-excel,application/pdf,*/*
Accept-Language:en-us
Accept-Encoding:gzip,deflate
User-Agent:Mozilla/4.0(compatible;MSIE5.5;WindowsNT4.0)
Host:localhost:9000
Connection:Keep-Alive
Cookie:JSESSIONID=F80F0F571FDE4873CFF3FF0B842D4938;mycookie=1051610231064
Acookiecontainsanameandavalue;thecookiecanalsohaveseveralotheroptionalattribute/valuepairs,whichareseparatedbysemicolons:
Domain
Specifiesthedomaintowhichthiscookiewillbesentinfuturerequests,asinDomain=.jspservletcookbook.com.ThedefaultvalueofthisoptionalattributeisthehostnameofthedomainthathassenttheSet-Cookieheader.
Path
Furtherdelineatesthepartofthewebsitethat,whenrequested,issentthecookiebytheclient.Mostcookiesgivethisattributeavalueof/.Forexample,ifonlythecustomercontextpathshouldreceivethecookie,thentheSet-Cookieheaderwouldincludethepath=/customerattribute/valuepair.Theclientwouldnotsendthecookievaluewhenmakinganyrequeststothedomainthatdonotincludethe/customercontextpath.
Expires
Specifiesthemaximumamountoftimetheuser'sbrowsershouldkeepthecookie.Thisattributeisadatestringrepresentingafuturedate.IfExpiresspecifiesapastdate,thenthecookieisdeleted.TheJavaCookieAPImanagesthisattributebycallingtheCookie
object'ssetMaxAge()method(seeRecipe10.1).
Version
Anoptionalvalueof0forNetscape'spreliminaryspecificationand1fortheRFC2109document.
Secure
TrueifthecookiecanbesentonlyoverasecureconnectionsuchasHTTPS.
Comment
Mayhaveasavalueadescriptionofthecookie'spurpose.
Abrowserisexpectedtosupport20cookiesforeachwebserver,300cookiestotal,andmaylimitcookiesizeto4KBeach,accordingtothejavax.servlet.http.CookieAPIdocumentation.Thecookienameandvaluecombinetorepresentthe4-KBlimit,accordingtotheNetscapepreliminaryspecification.Atypicalcookieisfarlessthan4KBinsize.
Theusercanalsodisablecookies,sothathisbrowserdoesnotsaveanyofthecookiesinaweb-serverresponse.Forexample,inNetscape7.1,themenucombinationEdit Preferences Privacy&SecurityCookiesallowsyoutopreventtheacceptanceofcookiesbychoosingthe"Disablecookies"radiobutton.Inthiscase,thewebdeveloperuses"URLrewriting"foranyclientsthathavedisabledcookies(seeRecipe11.7andRecipe11.8).
TheJavaservletAPIabstractsacookieasanobjectoftypejavax.servlet.http.Cookie.Therecipesinthischaptershowhowtocreatenewcookies,aswellasreadoralterexistingcookies,withbothservletsandJSPs.
Recipe10.1SettingaCookiewithaServlet
Problem
Youwanttosetacookieusingaservlet.
Solution
Createthejavax.servlet.http.Cookieobjectinaservlet,thensetthecookieonauser'smachinewiththejavax.servlet.http.HttpServletResponse.addCookie(Cookie
cookie)method.
Discussion
Insidetheservlet,createtheCookiebyinstantiatinganewCookieandcallingitssetter(ormutator)methods.TheCookieconstructorincludesthenameandvalueforthecookie:
Cookiecookie=newCookie("mycookie","the1cookie");
Example10-1createsacookieandsetsitspathattribute(asin:cookie.setPath(Stringpath))tothenameofthecontextpath(asin/home).Withthispathsetting,theclientwillnotsendthecookietotheserverunlesstheclientrequestsresourceswithinthespecifiedcontextpath.ThecodeusesHttpServletRequest.getContextPath()toprovidethevalueforthecookie'spathattribute.
Example10-1.Aservletthatsetsacookieanddisplayssomecookieinformation
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassCookieServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
Cookiecookie=null;
//GetanarrayofCookiesassociatedwiththisdomain
Cookie[]cookies=request.getCookies();
booleannewCookie=false;
//Getthe'mycookie'Cookieifitexists
if(cookies!=null){
for(inti=0;i<cookies.length;i++){
if(cookies[i].getName().equals("mycookie")){
cookie=cookies[i];
}
}//endfor
}//endif
if(cookie==null){
newCookie=true;
//Getthecookie'sMax-Agefromacontext-paramelement
//Ifthe'cookie-age'paramisnotsetproperly
//thensetthecookietoadefaultof-1,'neverexpires'
intmaxAge;
try{
maxAge=newInteger(
getServletContext().getInitParameter(
"cookie-age")).intValue();
}catch(Exceptione){
maxAge=-1;
}//try
//CreatetheCookieobject
cookie=newCookie("mycookie",""+getNextCookieValue());
cookie.setPath(request.getContextPath());
cookie.setMaxAge(maxAge);
response.addCookie(cookie);
}//endif
//getsomeinfoaboutthecookie
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Cookieinfo</title>");
out.println("</head>");
out.println("<body>");
out.println(
"<h2>Informationaboutthecookienamed\"mycookie\"</h2>");
out.println("Cookievalue:"+cookie.getValue()+"<br>");
if(newCookie){
out.println("CookieMax-Age:"+cookie.getMaxAge()+"<br>");
out.println("CookiePath:"+cookie.getPath()+"<br>");
}
out.println("</body>");
out.println("</html>");
}
privatelonggetNextCookieValue(){
//returnsthenumberofmillesecondssinceJan1,1970
returnnewjava.util.Date().getTime();
}
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
doGet(request,response);
}
}
Example10-1usesCookie.setMaxAge(intage)tospecifywhenthecookiewillexpireorbedeletedbythebrowser.Themethodparameterrepresentsthemaximumnumberofsecondsthatthecookiewillliveontheuser'smachineafteritiscreated.Theexamplecodegetsthevalueforthismethodfromacontext-paramelementinweb.xml,whichallowsawebdevelopertoconfigureoroptionallychangethisvalueinthedeploymentdescriptor.Hereisanexampleofacontext-paramelementthatprovidesavalueforacookie'sage:
<context-param>
<param-name>cookie-age</param-name>
<param-value>31536000</param-value>
</context-param>
Forexample,ifyouwantedthecookietolingerforoneyear(365x24x60x60seconds),youcouldusethiscode:
cookie.setMaxAge(31536000);
Userscandeleteacookiefromtheirmachine,regardlessofthemaximumagethatyouhavecreatedforit.Somebrowsersprovideawindowintoauser'scookies,withfeaturesthatallowtheusertoremoveoneormorecookies.Don'tassumethatbecauseyousetamaximumage,thecookiewillalwaysbeavailableonusers'machines.
Example10-1alsochecksfortheexistenceofacookieofthesamenamethatthecodeplanstogivethenewcookie(mycookie).Iftheuserhasnotalreadysentthemycookiecookie,thentheservletsetsanewcookieanddisplayssomeofthecookie'svaluesafterward.
Figure10-1showstheservletoutput.
Figure10-1.Aservletshowsinformationaboutanewcookie
ThecookievalueisarbitrarilysettoaStringshowingalargenumber,justtodemonstratehowtoprovidethevalueforacookie.Asmanycookiesneeduniquevalues,youcoulduseamethodwherebytheuser'semailaddressoruniquedatabaseIDisencodedandthenusedasthecookievalue.
SeeAlso
Recipe10.3onsettingacookiewithaJSP;Recipe10.4onusingaservlettoreadcookies;Recipe10.5onreadingcookievalueswithaJSP;Recipe10.6onalteringorremovinganexistingcookie;theRFC2109
documentdealingwithcookies:ftp://ftp.rfc-editor.org/in-notes/rfc2109.txt;Netscape'spreliminaryspecificationforcookies:http://wp.netscape.com/newsref/std/cookie_spec.html;theJavaCookieAPI:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/Cookie.html.
Recipe10.2CreatinganArrayfromAlloftheRequest'sCookies
Problem
Youwanttostoreallofthecookiescontainedbyaclient'srequestinaCookiearray.
Solution
UsetheHttpServletRequest.getCookies()method,whichreturnsanarrayofjavax.servlet.http.Cookieobjects.
Discussion
TocreateanarrayofCookiesrepresentingallofthecookiesincludedinarequest,usetheHttpServletRequest.getCookies()method.YoucanthenaccessthenameandvalueofacookiebycallingtheCookieclass'sgetName()andgetValue()methods.
ThecodeforaccessinganarrayofCookieslookslikeExample10-2.
Example10-2.CreatingaCookiearray
//servlet'sdoGetmethod
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
Cookiecookie=null;
//GetanarrayofCookiesassociatedwiththisdomain
Cookie[]cookies=request.getCookies();
//Checkforanullvalue,thendosomethingwithanyCookies
if(cookies!=null){//readeachCookievalue
}
//restoftheservlet
Onceacookiehasalreadybeencreated,thenexttimetheusersendsthecookieasarequestheader,theonlyinformationyoucanextractfromtheCookieobjectisitsnameandvalue.Youwillnotbeabletoderivethecookie'smaximumagefromtherequestheader,becausealltheheaderwillcontainistheCookieobject:headername,thenthenameandvalueofthecookie.
SeeAlso
Recipe10.1onsettingacookiewithaservlet;Recipe10.3onsettingacookiewithaJSP;Recipe10.4onusingaservlettoreadcookies;Recipe10.5onreadingcookievalueswithaJSP;Recipe10.6onalteringorremovinganexistingcookie;theRFC2109documentdealingwithcookies:ftp://ftp.rfc-editor.org/in-notes/rfc2109.txt;Netscape'spreliminaryspecificationforcookies:http://wp.netscape.com/newsref/std/cookie_spec.html;theJavaCookieAPI:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/Cookie.html.
Recipe10.3SettingaCookiewithaJSP
Problem
YouwanttouseaJSPtosetacookieonaclient.
Solution
WrapaJavaBeanaroundtheservletAPIforcreatingcookies.ThenusethebeanintheJSPwiththejsp:useBeanstandardaction.
Discussion
AJSPcanuseaJavaBeantocreatethecookieandsetthecookieontheclient.Example10-3createsaninstanceofaJavaBeanoftypecom.jspservletcookbook.CookieBeanusingthejsp:useBeanstandardaction.ThentheJSPsetsafewbeanproperties.ThebeanwillpassthroughthepropertyvaluestothecookiethatitisgeneratingfortheJSP.TheJSPusesjsp:setPropertytosetthefollowingcookieproperties:
Thecookiename(bakedcookieinthecode).
Themaximumnumberofsecondsthebrowserwillholdontothecookie(roughlyoneyearinExample10-2).Thisnumberisconvertedtoareadablefuturedateforthecookie'sExpiresattribute.
Thepathontheserverassociatedwiththiscookie.OncetheJSPhassentthiscookietotheclient,theclientwillreturntheassociated
cookieonlyintherequestheadersforrequeststhatcontainthespecifiedcontextpath(suchas/home).Forexample,ifthecookieissetbytheJSPfileto/home/cookieSet.jsp,onlyrequestsforresourcesin/homewillincludeaCookieheader.
Example10-3.AJSPthatsendsacookietoaclient
<jsp:useBeanid="cookieBean"class="com.jspservletcookbook.CookieBean"/>
<jsp:setPropertyname="cookieBean"property="name"value="bakedcookie"/>
<%--set'Expires'attributetoaboutoneyearfromnow--%>
<jsp:setPropertyname="cookieBean"property="maxAge"value=
"<%=(365*24*60*60)%>"/>
<jsp:setPropertyname="cookieBean"property="path"value="<%=request.getContextPath()
%>"/>
<jsp:setPropertyname="cookieBean"property="cookieHeader"value="<%=response%>"/>
<html>
<head><title>CookieMaker</title></head>
<body>
<h2>Hereisinformationaboutthenewcookie</h2>
Name:<jsp:getPropertyname="cookieBean"property="name"/><br>
Value:<jsp:getPropertyname="cookieBean"property="value"/><br>
Path:<jsp:getPropertyname="cookieBean"property="path"/>
</body>
</html>
TheJSPpassesalongtheHttpServletResponseobjecttoitswrapperbean,sothatthebeancancallresponse.addCookie(Cookiecookie)tosendtheclientthenewcookie.Theresponseobjectispassedtothebeanusingthiscode(seethesetCookieHeader()methodinExample10-4):
<jsp:setPropertyname="cookieBean"property="cookieHeader"value=
"<%=response%>"/>
ThebottomoftheJSPdisplayssomeofthenewcookie'svalues.Figure10-2showstheJSP'soutputinawebbrowser.Repeatedlyrequesting
theJSPwilloverwritetheexistingcookiewithanewone.
Figure10-2.AJSPshowsinformationaboutanewcookie
Example10-4showsthecodefortheCookieBeanitself,whichisratherlengthyduetoallthegetterandsettermethods.
ThisJavaBeanclassmustbeplacedintheWEB-INF/classesdirectoryofthewebapplication(includingadirectorystructurethatmatchesthebean'spackagename)sothatthewebcontainercanloadtheclass.ThebeancouldalsobearchivedinaJARfilethatisplacedinWEB-INF/lib;however,theJARwouldstillhavetocontainadirectorystructurethatmatchesthebean'spackagename.
YoucansetthecookievalueintheJSP(whichisnotdoneinExample10-3)bycallingthebean'ssetValue(Stringvalue)methodviajsp:setProperty:
<jsp:setPropertyname="cookieBean"property="value"value="newvalue"/>
ThebeanhastoimporttheCookieandHttpServletResponseclasses,becauseitusesthemtomakethenewcookie,thensendthecookietotheclient.Example10-4wrapsitsownmethodsaroundsome
oftheCookieclassmethods,suchassetValue()andsetMaxAge().
Example10-4.AJavaBeanformakingcookies
packagecom.jspservletcookbook;
importjavax.servlet.http.HttpServletResponse;
importjavax.servlet.http.Cookie;
publicclassCookieBean{
privateCookiecookie=null;
publicCookieBean(){}
//setthecookiename
publicvoidsetName(Stringname){
if(name==null||(name.equals("")))
thrownewIllegalArgumentException(
"Invalidcookienamesetin:"+getClass().getName());
cookie=newCookie(name,""+newjava.util.Date().getTime());
}
//setthecookievalue
publicvoidsetValue(Stringvalue){
if(value==null||(value.equals("")))
thrownewIllegalArgumentException(
"Invalidcookievaluesetin:"+getClass().getName());
if(cookie!=null)
cookie.setValue(value);
}
publicvoidsetMaxAge(intmaxAge){
if(cookie!=null)
cookie.setMaxAge(maxAge);
}
publicvoidsetPath(Stringpath){
if(path==null||(path.equals("")))
thrownewIllegalArgumentException(
"Invalidcookiepathsetin:"+getClass().getName());
if(cookie!=null)
cookie.setPath(path);
}
publicvoidsetCookieHeader(HttpServletResponseresponse){
if(response==null)
thrownewIllegalArgumentException(
"InvalidHttpServletResponsesetin:"+getClass().getName());
if(cookie!=null)
response.addCookie(cookie);
}
publicStringgetName(){
if(cookie!=null)
returncookie.getName();
else
return"unavailable";
}
publicStringgetValue(){
if(cookie!=null)
returncookie.getValue();
else
return"unavailable";
}
publicStringgetPath(){
if(cookie!=null)
returncookie.getPath();
else
return"unavailable";
}
}
IftheJSPfailstousejsp:setPropertytocallthebean'ssetCookieHeader(HttpServletResponseresponse)method,thenthecookieiscreatedbutneverincludedintheresponseheaderssenttotheclient.Inthisdesign,youallowtheusertosetsomeoptionalcookieattributes(suchasPath)beforesheexplicitlysendsthecookieaspartoftheresponse.
SeeAlso
Recipe10.1onsettingacookiewithaservlet;Recipe10.2oncreatinganarrayfromalloftherequest'scookies;Recipe10.4onusingaservlettoreadcookies;Recipe10.5onreadingcookievalueswithaJSP;Recipe10.6onalteringorremovinganexistingcookie;theRFC2109documentdealingwithcookies:ftp://ftp.rfc-editor.org/in-notes/rfc2109.txt;Netscape'spreliminaryspecificationforcookies:http://wp.netscape.com/newsref/std/cookie_spec.html;theJavaCookieAPI:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/Cookie.html.
Recipe10.4ReadingCookieValueswithaServlet
Problem
Youwanttoreadcookievaluesfromaclientusingaservlet.
Solution
CreateaJavaarrayofjavax.servlet.http.CookieobjectsbycallingtheHttpServletRequest.getCookies()method.Thencyclethroughthearray,accessingeachcookieandvalueasneeded.
Discussion
ThewebuserwillsendcookiestoawebsiteonlyiftheuseroriginallyreceivedSet-Cookieheadersfromthatdomain.Inaddition,ifthecookiewassetwithaPathattributespecifyingacontextpath,thentheservletcanaccessthecookieonlyiftheservletisalsoassociatedwiththecontextpath.Asaresult,alwaystestthereturnvalueoftherequest.getCookies()method(whichreturnsanarrayofCookieobjects)toseeifitisnull,indicatingthattheuserhasnotsentanycookies,beforeoperatinguponit.
Example10-5displaysthevalueofanyfoundcookiesinawebbrowser.TheCookieReaderclassusesthejavax.servlet.http.Cookie.getName()andgetValue()methodsinordertodisplaythisinformation.
Example10-5.Acookie-readingservlet
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassCookieReaderextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
Cookiecookie=null;
//GetanarrayofCookiesassociatedwiththisdomain
Cookie[]cookies=request.getCookies();
booleanhasCookies=false;
//ifcookiescontainsanarrayandnotanullvalue,
//thenwecandisplayinformationaboutthecookies.
if(cookies!=null)
hasCookies=true;
//displaythename/valueofeachcookie
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Cookieinformation</title>");
out.println("</head>");
out.println("<body>");
if(hasCookies){
out.println(
"<h2>Thenameandvalueofeachfoundcookie</h2>");
for(inti=0;i<cookies.length;i++){
cookie=cookies[i];
out.println(
"Nameofcookie#"+(i+1)+":"+cookie.getName()+"<br>");
out.println(
"Valueofcookie#"+(i+1)+":"+
cookie.getValue()+"<br><br>");
}//for
}else{
out.println(
"<h2>Thisrequestdidnotincludeanycookies</h2>");
}
out.println("</body>");
out.println("</html>");}
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
doGet(request,response);
}
}
Thejavax.servlet.http.Cookieclassisanabstractionofacookiethathasgetterandsettermethodsforacookie'sattributes,suchasitsname,value,path,andsecureattributes.However,whenyouretrieveacookie,youcanonlygetitsnameandvalue,becausethisistheonlyinformationthattheclientincludesintherequestheader.TheCookierequestheaderlookslike:
Cookie:JSESSIONID=F80F0F571FDE4873CFF3FF0B842D4938;mycookie=1051610231064
Forexample,callingCookie.getPath()onaretrievedcookiewillreturnnull,evenifthecookiewasoriginallysetwithavalidpathattribute,suchas/mypath.YoucanonlyaccessthesevaluesintheservletorJSPthatcreatesthecookieobjectinthefirstplace(seeRecipe
10.1andRecipe10.3).
Figure10-3showshowawebbrowserdisplaysthisservlet'soutput.
Figure10-3.Aservletdisplayscookieinformation
SeeAlso
Recipe10.1onsettingacookiewithaservlet;Recipe10.2oncreatinganarrayfromalloftherequest'scookies;Recipe10.3onsettingacookiewithaJSP;Recipe10.5onreadingcookievalueswithaJSP;Recipe10.6onalteringorremovinganexistingcookie;theRFC2109documentdealingwithcookies:ftp://ftp.rfc-editor.org/in-notes/rfc2109.txt;Netscape'spreliminaryspecificationforcookies:http://wp.netscape.com/newsref/std/cookie_spec.html;theJavaCookieAPI:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/Cookie.html.
Recipe10.5ReadingCookieValueswithaJSP
Problem
YouwanttoreadcookievalueswithaJSP.
Solution
UsetheJSTLanditscookieimplicitobjecttodisplaythenameandvalueofanycookiesfoundintherequest.
Discussion
TheJSTLanditsELhaveacookieimplicitobject(avariablethatisautomaticallyavailabletoJSPorELcode)thatyoucanuseinJSPstodisplayanycookienamesandvalues.FormoreinformationontheJSTLandEL,seeChapter23.
YoucanaccessthecookieimplicitobjectinJSPcodethisway:
${cookie}
Thisimplicitobjectevaluatestoajava.util.Maptypewhosevaluesyoucaniterateoverwiththec:forEachJSTLtag.Eachiterationofc:forEachreturnsajava.util.Map.Entry,whichencapsulatesakey/valuepair.Thekeyisthenameofthecookie;thevalueisajavax.servlet.http.Cookieobject.
Example10-6usesthiscodetoretrieveaCookieobjectfromtheMapofavailablecookies:
<c:forEachvar="cookieVal"items="${cookie}">
Thevarattributeofc:forEachcontainsaMap.Entryobjectwhosekeyisthecookiename;thevalueistheCookieobject.Thecodeusesc:outtagstodisplaythecookienamesandvaluesintheJSP.Thisoddsyntaxdisplaysthevalueofeachcookie:
<c:outvalue="${cookieVal.value.value}"/>
ThecodecookieVal.valueevaluatestothejavax.servlet.http.Cookieobject.Thefullphrase${cookieVal.value.value}istheequivalentofcallingCookie.getValue().
Example10-6.AJSPthatreadscookienamesandvalues
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<body>
<%--checkwhethertherequestcontainsanycookies--%>
<c:choose>
<c:whentest="${emptycookie}">
<h2>Wedidnotfindanycookiesintherequest</h2>
</c:when>
<c:otherwise>
<h2>Thenameandvalueofeachfoundcookie</h2>
<c:forEachvar="cookieVal"items="${cookie}">
<strong>Cookiename:</strong><c:outvalue="${cookieVal.key}"/><br>
<strong>Cookievalue:</strong><c:outvalue=
"${cookieVal.value.value}"/><br><br>
</c:forEach>
</c:otherwise>
</c:choose>
</body>
</html>
Figure10-4showstheJSPdisplayingtheavailablecookieinformation.
Figure10-4.OutputofthecookieReader.jsppage
MakesuretoincludethetaglibdirectivefortheJSTLcorelibraryatthetopofyourJSP,sothatyoucanusetheJSTLtagstoviewanycookievalues:
<%@tagliburi=
"http://java.sun.com/jstl/core"prefix="c"%>
Useuri=http://java.sun.com/jsp/jstl/corewhenusingJSTL1.1
SeeAlso
Recipe10.1onsettingacookiewithaservlet;Recipe10.2oncreatinganarrayfromalloftherequest'scookies;Recipe10.3onsettingacookiewithaJSP;Recipe10.4onusingaservlettoreadcookies;Recipe10.6onalteringorremovinganexistingcookie;theRFC2109
documentdealingwithcookies:ftp://ftp.rfc-editor.org/in-notes/rfc2109.txt;Netscape'spreliminaryspecificationforcookies:http://wp.netscape.com/newsref/std/cookie_spec.html;TheJavaCookieAPI:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/Cookie.html.
Recipe10.6AlteringorRemovingaCookieThatHasAlreadyBeenSet
Problem
Youwanttooverwriteorremoveanexistingcookie.
Solution
Sendacookiewiththesamenameandpathasanexistingcookietooverwritetheexistingcookie.Todeleteacookie,sendacookiewiththesamenameandpathbutsettheExpiresattributetoadateinthepast.
Discussion
Youcanoverwriteacookieandoptionallyprovidedifferentvaluesforitsattributes(suchasthecookievalue)byincludingacookieinaresponseheaderthathasthesamenameandpathasanexistingcookie.Forexample,imagineaservlethassetacookieontheclientwiththefollowingresponseheader:
Set-Cookie:newcookie=1051642031398;Expires=Wed,28-Apr-200418:47:11GMT;Path=/home
Thiscookiecanbeoverwrittenontheclientbychangingitscookievalue,butnotthenameandpath:
Set-Cookie:newcookie=A1lnew;Expires=Wed,28-Apr-200418:52:50GMT;Path=/home
Thisresponseheaderwillreplacenewcookiewithacookieofthesamename.Thenewversionhasanewvalue(A1lnew)andanExpiresattributevalue.
DeletingaCookie
YoucandeleteacookiebysendingaresponseheadertotheclientwiththesamecookienameandPathvalue,butwithanExpiresattributevaluethatrepresentsadateinthepast.WithJava'sCookieAPI,yousimplycallthejavax.servlet.http.Cookie.setMaxAge()methodwithanargumentvalueof0.Example10-7istheJSPofRecipe10.2.ThistimetheJSPisdeletingmycookiebysettingthemaxAgepropertyto0usingjsp:setProperty.
Example10-7.Deletinganexistingcookie
<jsp:useBeanid="cookieBean"class="com.jspservletcookbook.CookieBean"/>
<jsp:setPropertyname="cookieBean"property="name"value="mycookie"/>
<%--deletethecookiebycallingCookie.setMaxAge(0)--%>
<jsp:setPropertyname="cookieBean"property="maxAge"value="0"/>
<jsp:setPropertyname="cookieBean"property="value"value="finished"/>
<jsp:setPropertyname="cookieBean"property="path"value=
"<%=request.getContextPath()%>"/>
<jsp:setPropertyname="cookieBean"property="cookieHeader"value=
"<%=response%>"/>
<%--restofJSPcontinues--%>
CookiescanbedeletedonlybyaSet-Cookieresponseheaderemanatingfromthesamedomainthatcreatedthecookie,withthesamecookienameandPathattribute.HereiswhattheresponseheaderfromthedeletingJSPlookslike:
HTTP/1.1200OK
Content-Type:text/html;charset=ISO-8859-1
Set-Cookie:mycookie=finished;Expires=Thu,01-Jan-197000:00:10GMT;Path=/home
Transfer-Encoding:chunked
Date:Tue,29Apr200319:18:59GMT
Server:ApacheCoyote/1.0
NotethattheExpiresattributevalueisadateinthepast.Asaresult,theclientwillnolongersendthemycookiecookieinitsrequestheaderswhenitmakesarequesttothesamedomainatthe/homecontextpath.However,itmaysendothercookies(withdifferentnames)thatwerecreatedduringpriorvisitstothesamedomainandcontextpath.
Thebrowserusercandeleteacookiefromhismachineanytimehewants,soalwaysplanaccordingly.
SeeAlso
Recipe10.1onsettingacookiewithaservlet;Recipe10.2oncreatinganarrayfromalloftherequest'scookies;Recipe10.3onsettingacookiewithaJSP;Recipe10.4onusingaservlettoreadcookies;Recipe10.5onreadingcookievalueswithaJSP;theRFC2109documentdealingwithcookies:ftp://ftp.rfc-editor.org/in-notes/rfc2109.txt;Netscape'spreliminaryspecificationforcookies:http://wp.netscape.com/newsref/std/cookie_spec.html;theJavaCookieAPI:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/Cookie.html.
Chapter11.SessionTracking
Introduction
Recipe11.1.SettingtheSessionTimeoutinweb.xml
Recipe11.2.SettingtheSessionTimeoutinAllTomcatWebApplications
Recipe11.3.SettingtheSessionTimeoutProgrammatically
Recipe11.4.CheckingifaSessionExistsinanHttpServletRequest
Recipe11.5.TrackingSessionActivityinServlets
Recipe11.6.TrackingSessionActivityinJSPs
Recipe11.7.UsingURLRewritinginaJSP
Recipe11.8.UsingURLRewritinginaServlet
Recipe11.9.UsingaListenertoTracktheSessionLifecycle
Recipe11.10.UsingaListenertoMonitorSessionAttributes
Recipe11.11.UsingaFiltertoMonitorSessionAttributes
Introduction
ThischapterdescribeshowtomonitorsessionsinservletsandJSPs.Asessionrepresentsaninteractionbetweenawebuserandawebapplication.TheHypertextTransferProtocol(HTTP)isastatelessprotocol,meaningthatitisnotdesignedtomaintainstate,ortheprogressofasingleuserassheinteractswithawebserverbyexchangingHTTPrequestsandresponses.EachrequestforaJSPorservlet,atleastfromtheHTTPserver'spointofview,isconsideredseparatefromotherrequestsandnotassociatedwiththesameuser.Manywebapplications,however,needtofollowauser'sprogressstepbystepthroughouttheapplication,tokeeptrackofherpurchaseditemsand/orpreferences.
Forexample,whenauserbuysbooksatAmazon.com,thewebsitemonitorswhatisaddedtoorremovedfromthecustomer'sshoppingcartandusesthisinformationduringthecheckoutandpaymentprocess.Inaddition,Amazon.comshowsuserswhichbookstheyhavelookedatduringtheircurrentsession.Sequentialvisitsbyasingleusertoane-commercesitelikethisareconsideredpartsofonesession.
Webapplicationscommonlyusecookiesinordertoimplementsessions.Allservletcontainershavetosupporttheuseofcookiestotracksessions,accordingtotheServletv2.3and2.4specifications.Acookieisasmallpieceofinformationthatisstoredbytheclientwebbrowserinresponsetoaresponseheaderissuedbythewebserver.CookiesaredescribedinmoredetailinChapter10,butsincetheyarecentraltothesessionconcept,Iincludeabriefoverviewoftheiruseinsessiontrackinghere.
Whenauserrequestsapagefromawebserver,theserverrespondswithacollectionofname/valuepairscalledresponseheaders,alongwiththeHTMLresponse.TheseheadersmayincludeonelabeledSet-Cookie,whichrequeststhattheclientstoresomestateinformationlocally.TheonlyrequiredelementoftheSet-CookieHTTPresponseheaderisthecookienameandvalue.Thecookiemayincludeother
piecesofinformationseparatedbysemicolons.ThecookiethatJavawebcontainerssetinordertoimplementsessiontrackinglookslikejsessionid=cookie-value,wherecookie-valueisusuallyalongnumericstringofbytesusinghexadecimalnotation.Accordingtotheservletspecificationv2.3,thiscookie'snamemustbeJSESSIONID.Somewebcontainersgeneratethenameinlowercase,however,likeTomcat.Atypicalsession-relatedcookielookslikethefollowing:
jsessionid=3CAF7CD0A0BFF5076B390CCD24FD8F0D
ThecookievaluerepresentsthesessionID.ThisIDuniquelyidentifiestheuserfortheperiodwhenheismakingrequeststothewebserver.Forexample,if10usersareinteractingwiththewebapplicationatthesametime,thewebserverassignsthem10uniquesessionIDs.Additionally,ifapersonsitsdownathisPCandconnectswiththewebapplicationusingInternetExplorer,thenmovesovertoaconnectedlaptopandopensupSafaritothesamewebapplication,thosebrowserswillbeassociatedwithtwodifferentsessionIDs.Thewebserverdoesnothaveanywayofknowingthatthesamepersonisinteractingwiththewebapplicationfromtwodifferentbrowsersatthesametime,particularlyifheisconnectingfrombehindaproxyserver.However,aslongastheuserworkswithasinglebrowserandthatuser'ssessionhasnotyettimedout,awebservercantrackthatuser'sactions,andassociatethemasonesession.
DisabledCookies
Whatiftheuserblockscookies?Webbrowserstypicallyallowthedisablingofcookiesintheuserpreferences.ServersmayalsousetheSecureSocketsLayer(SSL),whichhasabuilt-insession-trackingmechanism.Inaddition,URLrewritingisacommonfallbackmethodofsessiontracking.URLrewritinginvolvesaddingthesessionIDasapathparametertotheURLwhenlinkingfromonepagetothenext,sothatthenextpagehasaccess(withoutcookies)tothesessionID.TheseURLslooklikethis:
/home/default.jsp;jsessionid=3CAF7CD0A0BFF5076B390CCD24FD8F0D
AsmostpagerequestsineverydaywebusearenotmadeusingSSL,youshouldcodeyoursessiontracking-relatedwebcomponentstoaccommodateURLrewriting.
Recipe11.1SettingtheSessionTimeoutinweb.xml
Problem
Youwanttoconfigureatimeoutperiodforthewebapplicationinthedeploymentdescriptor.
Solution
Createasession-configelementinweb.xml.
Discussion
Thelengthoftimethatasessionlastsbeforetheserverinvalidatesthesessionandunbindsanyofitsobjectsisanimportantcomponentofyourwebapplication.InTomcat4.1.x,thedefaulttimeoutperiodforasessionis30minutes.Ifanyrequeststhatareassociatedwiththesessionhavebeeninactiveforthatperiod,thesessiontimesout.Iftheuserdecidestoreturntothewebapplicationafter30minutes,usingthesamebrowser,thenanewsessioniscreatedforhim.Example11-1showshowtosetyourowntimeoutperiodforsessions.
Example11-1.Configuringthesessiontimeout
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<!--filter,listener,servlet,andservlet-mappingelementsprecedesession-config-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>
Placeonenestedsession-timeoutelementwithinthesession-config.Thetimeoutisexpressedasminutes,andoverridesthedefaulttimeout(whichis30minutesinTomcat,forexample).However,theHttpSession.getMaxInactiveInterval()methodinaservletreturnsthetimeoutperiodforthatsessioninseconds;ifyoursessionisconfiguredinweb.xmlfor15minutes,getMaxInactiveInterval()returns900.
Anotherwaytoconfigureatimeoutvalueforaservletistousetheinit-paramelementinweb.xml,asshowninExample11-2.
Example11-2.Addinganinit-paramtoaservlettosetasessiontimeoutinterval
<servlet>
<servlet-name>Cart</servlet-name>
<servlet-class>com.jspservletcookbook.TimeoutSession</servlet-class>
<init-param>
<param-name>timeout</param-name>
<param-value>600</param-value>
</init-param>
</servlet>
Theservletelementinthiswebapplication'sweb.xmlfilehasanested
init-param,whichcreatesaparametercalledtimeout.TheCartservlettakestheparametervalue(600seconds,equivalentto10minutes)andpassesittothesession.setMaxInactiveInterval(intseconds)method.Example11-3showsthedoGet()methodoftheservlet,whichsetsthesessiontimeoutvariabletotheconfiguredparametervalue.
Example11-3.Usinginitparameterstosetaservlet'ssessiontimeout
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
HttpSessionsession=request.getSession();
//initiallysettodefaulttimeoutinterval
int_default=session.getMaxInactiveInterval();
inttimeout=_default;
try{
timeout=newInteger(getInitParameter("timeout")).intValue();
}catch(NumberFormatExceptionnfe){
//reportanyproblemswiththeconfiguredvalueinweb.xml
log("Problemwithconfiguringsessiontimeoutin:"+
getClass().getName());
}//try
//nowsetthesessiontotheconfiguredtimeoutperiod
if(timeout!=_default&&timeout>-2)
session.setMaxInactiveInterval(timeout);
out.println("<html>");
out.println("<head>");
out.println("<title>CartServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("Thetimeoutintervalis:"+
session.getMaxInactiveInterval());
out.println("</body>");
out.println("</html>");
}
Figure11-1showstheresultofrunningthisservletinabrowserwindow.
Figure11-1.Dynamicallychangingthesessiontimeout
Thesessiontimeoutischangedonlyiftheconfiguredvalueisdifferentthantheinitialvalue,andifthevalueisgreaterthan-2:
if(timeout!=_default&&timeout>-2)
session.setMaxInactiveInterval(timeout);
Atimeoutintervalcanbesetto-1,whichisdefinedbytheServletv2.4specificationasasessionthatneverexpires.
Thisbehaviormaynotbeimplementedconsistentlyfromservertoserver.
Asmentionedbefore,sessionsareimplementedthemajorityofthetimeascookies.Chapter10includesrecipesdescribingthehandlingofcookiesinJSPsandservlets.
SeeAlso
Recipe11.2andRecipe11.3onconfiguringthesessiontimeoutinTomcatwebapplications;Chapter1onweb.xml;Chapter7oftheServletv2.3and2.4specificationsonsessions;thesession-trackingsectionsofJavaServletProgrammingbyJasonHunter(O'Reilly)andJavaServerPagesbyHansBergsten(O'Reilly).
Recipe11.2SettingtheSessionTimeoutinAllTomcatWebApplications
Problem
YouwanttoconfigureasessiontimeoutperiodforallofthewebapplicationsthatarerunningwithinaninstanceofTomcat.
Solution
Setthesessiontimeoutwithinthesession-configelementin<Tomcat-installation-directory>/conf/web.xml.
Discussion
YoucansetthesessiontimeoutforallwebapplicationsbyconfiguringTomcat'sdefaultconf/web.xmlfile.Ifthedeploymentdescriptorforaparticularwebapplicationdoesnothaveasession-configelement,thentheapplicationusesthevaluesetinconf/web.xmlasthedefaultsessiontimeout.Thecontentofthesession-timeoutelement(nestedwithinsession-config)representsthetimeinminutesuntilaninactivesessionexpires.
Example11-4showsthesession-configelementinthedefaultweb.xmlfileforTomcat4.1.x,withtheaccompanyingXMLcomment.
Example11-4.Thesession-configelementinsideofthedefaultTomcatweb.xmlfile
<!--===================DefaultSessionConfiguration================-->
<!--Youcansetthedefaultsessiontimeout(inminutes)forallnewly-->
<!--createdsessionsbymodifyingthevaluebelow.-->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
Onapplicationdeployment,Tomcatprocessesitsdefaultweb.xmlfile,followedbythedeploymentdescriptorsforeachwebapplication.Yourownsession-configelementoverridestheonespecifiedinconf/web.xml.Itisusuallyabetterideatoconfiguresessionsforeachwebapplicationindividually,particularlyiftheyaredesignedtobeportable.
SeeAlso
Recipe11.1onconfiguringthesessiontimeout;Recipe11.3onsettingthesessiontimeoutprogrammatically;Recipe11.4oncheckingthevalidityofasession;Chapter1onweb.xml;Chapter7oftheServletv2.3and2.4specificationsonsessions;thesession-trackingsectionsofJavaServletProgrammingbyJasonHunter(O'Reilly)andJavaServerPagesbyHansBergsten(O'Reilly).
Recipe11.3SettingtheSessionTimeoutProgrammatically
Problem
Youwanttosetasessiontimeoutinyourservletcode.
Solution
UsetheHttpServletRequestobject'sgetSession()methodtogetareferencetotheHttpSessionobject.ThenchangethetimeoutperiodprogrammaticallybyusingtheHttpSession.setMaxInactiveInterval(intseconds)method.
Discussion
TheHttpSession.setMaxInactiveInterval(intseconds)methodsetsthetimeoutforasessionindividually,sothatonlytheparticularsessionobjectbeingoperateduponisaffected.Otherservletsthatdosessiontrackinginthewebapplicationstillusethesession-timeoutvalueinweb.xmlor,intheabsenceofthiselement,theserver'sdefaultsession-timeoutvalue.Example11-5checksthetimeoutperiodforasession,thenresetsthattimeoutperiodto20minutes.
Example11-5.Resettingadefaulttimeoutperiod
packagecom.jspservletcookbook;
importjava.util.Date;
importjava.text.DateFormat;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSimpleSessionextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
HttpSessionsession=request.getSession();
out.println("<html>");
out.println("<head>");
out.println("<title>SimpleSessionTracker</title>");
out.println("</head>");
out.println("<body>");
out.println("<h2>SessionInfo</h2>");
out.println("sessionID:"+session.getId()+"<br><br>");
out.println("TheSESSIONTIMEOUTperiodis"+
session.getMaxInactiveInterval()+"seconds.<br><br>");
out.println("Nowchangingitto20minutes.<br><br>");
session.setMaxInactiveInterval(20*60);
out.println("TheSESSIONTIMEOUTperiodisnow"+
session.getMaxInactiveInterval()+"seconds.");
out.println("</body>");
out.println("</html>");
}
}
Figure11-2showstheresultofrequestingthisservletinawebbrowser.
Figure11-2.Gettingsession-timeoutinfo
ThisservletgetstheHttpSessionobjectwiththeHttpServletRequestclass'sgetSession()method.
Whatevertheservlet'sdefaulttimeoutperiodis,say,30minutes,Example11-5changestheaccessedsession'stimeoutto20minutes:
session.setMaxInactiveInterval(20*60);
Remember,thismethodaltersthedefaultsession-timeoutintervalonlyforthesessionassociatedwiththeuserswhorequestthisservlet.Whywouldsomeusersgetadifferenttimeoutintervalthanothers?Perhapsweb-usertestingatyourorganizationhasindicatedthatasessiontimeoutoffiveminutesismoreappropriateforyourshoppingcart-relatedservlets,whereassomechart-ormap-creationservletsrequirethedefaulttimeoutof30minutesormore,sincetheirusersmightlingeroverthecompleximagesintheirbrowsersforalongperiod.
Inmostwebapplications,thesessiontimeoutisset(oraltered)inthe
deploymentdescriptor,andyouwillnothavetodynamicallychangethetimeoutintheservletcode.
SeeAlso
Recipe11.1onconfiguringthesessiontimeout;Recipe11.2onsettingthesessiontimeoutinallTomcatapplications;Recipe11.4oncheckingthevalidityofasession;Chapter1onweb.xml;Chapter7oftheServletv2.3andv2.4specificationsonsessions;thesession-trackingsectionsofJavaServletProgrammingbyJasonHunter(O'Reilly)andJavaServerPagesbyHansBergsten(O'Reilly).
Recipe11.4CheckingifaSessionExistsinanHttpServletRequest
Problem
Youwanttocheckifawebapplicationuserhasavalidsession.
Solution
UsetheHttpServletRequestobject'sgetSession(false)methodtofindoutwhethertheHttpSessionobjectisnull.
Discussion
Somewebcomponentsaredesignedtomonitorifasessionisvalid,thenoptionallyredirectorforwardtheusertoanotherwebcomponentbasedonthevalidityofthesession.Forexample,imaginethatausermakesarequesttoacomponentthatexpectstofindacustomobjectstoredinthesessionobject,suchasa"shoppingcart."Youwanttocheckifthesessionisvalid;however,youdonotwanttocreateanewsessionfortherequestifthesessionisnotvalid,becauseanotherwebcomponentfartherbackinthechainofapplicationcomponentsisresponsibleforcreatingnewsessionsandpopulatingthemwithshoppingcartitems.TheusermayhaveenteredthewebapplicationatStep3insteadofStep1.Inthiscase,ifthesessionisinvalid,therequestisforwardedtoanotheraccesspointintheapplication(suchasaloginscreen).
IfyoucalltheHttpServletRequestobject'sgetSession(false)methodandthemethodreturnsfalse,thentheuserdoesnothaveavalidsessionandtherequestobjecthasnotcreatedanewsessionfor
her.
EitherHttpServletRequest.getSession(true)orgetSession()willattempttocreateanewsession.
Example11-6isaservletthatchecksauser'ssession,thenredirectstheusertoanotherwebcomponentifthesessionobjectisnull.
Example11-6.Checkingifasessionisvalidornot
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSessionCheckextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
HttpSessionsession=request.getSession(false);
if(session==null){
response.sendRedirect("/myproj/login.jsp");
}else{
response.sendRedirect("/myproj/menu.jsp");
}
}
}
IfthesessioninExample11-6isnull,theservletredirectstherequesttothelogin.jsppageatthecontextpath/myproj.Ifthesessionobjectisvalid,therequestisredirectedtothe/myproj/menu.jspcomponent.
TheHttpServletResponse.sendRedirect(Stringlocation)methodsendstheclientanHTTPresponsethatlookslikethis:
HTTP/1.1302MovedTemporarily
Location:
http://localhost:9000/dbproj/login.jsp
Content-Type:text/html;charset=ISO-8859-1
...
TheclientthensendsanotherrequestfortheURLspecifiedinthelocationheaderoftheHTTPresponse.
SeeAlso
Recipe11.1andRecipe11.3onconfiguringthesessiontimeout;Chapter1onweb.xml;Chapter7oftheServletv2.3and2.4specificationsonsessions;thesession-trackingsectionsofJavaServletProgrammingbyJasonHunter(O'Reilly)andJavaServerPagesbyHansBergsten(O'Reilly).
Recipe11.5TrackingSessionActivityinServlets
Problem
Youwanttouseaservlettotrackthecreationtimeandlast-accessedtimeforasession.
Solution
UsetheHttpServletRequestobject'sgetSession()methodtogetareferencetotheHttpSessionobject.ThencalltheHttpSession.getCreationTime()andHttpSession.getLastAccessedTime()methodsonthatobject.
Discussion
ThisrecipedescribeshowtousetheHttpSessionAPItofindoutthecreationtimeandthelast-accessedtimeforasession.Howwouldawebapplicationusethisinformation?Forone,youmightwanttomonitorthepatternofrequestactivityinawebapplicationbycomparingthesessioncreationtime,thelast-accessedtime,andthecurrenttime.Forexample,thedifferencebetweenthecreationtimeandthecurrenttime(measuredinseconds)wouldindicatehowlongthewebapplicationhadbeentrackingaparticularuser'ssession.
ThemethodHttpSession.getLastAccessedTime()returnsthetime(asalongdatatype)ofthelasttimetheusermadearequestassociatedwithaparticularsession.
AservletthatcallsgetLastAccessedTime()representsthemostcurrent
requestassociatedwiththesession.Inotherwords,thetimeatwhichtheuserrequeststheservletthatcallsgetLastAccessedTime()becomesthelastaccessedtime.
Example11-7displaysthecurrenttime,aswellasthesession'screationandlast-accessedtimes.
TheHttpServletRequest.getSession()methodassociatesanewsessionwiththerequestifonedoesnotalreadyexist.TheHttpServletRequest.getSession(false)methodreturnsnullifasessionisnotassociatedwiththerequestanditwillnotcreateanewHttpSessionfortheuser.SeeRecipe11.4.
Example11-7.CallingHttpSessionmethodsinaservlet
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjava.util.Date;
importjava.text.DateFormat;
importjava.util.Enumeration;
publicclassSessionDisplayextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
HttpSessionsession=request.getSession();
DatecreationTime=newDate(session.getCreationTime());
DatelastAccessed=newDate(session.getLastAccessedTime());
Datenow=newDate();
DateFormatformatter=
DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.MEDIUM);
out.println("<html>");
out.println("<head>");
out.println(
"<title>DisplayingtheSessionCreationand"+
"Last-AccessedTime</title>");
out.println("</head>");
out.println("<body>");
out.println("<h2>SessionCreationandLast-AccessedTime</h2>");
out.println(
"Thetimeanddatenowis:"+formatter.format(now)+
"<br><br>");
out.println("Thesessioncreationtime:"+
"HttpSession.getCreationTime():"+
formatter.format(creationTime)+"<br><br>");
out.println("Thelasttimethesessionwasaccessed:"+
HttpSession.getLastAccessedTime():"+
formatter.format(lastAccessed));
out.println("</body>");
out.println("</html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
doGet(request,response);
}//doPost
}
AnexampleofabrowserdisplayforthisservletisshowninFigure11-3.
Figure11-3.Findingoutasession'screationandlast-accessedtimes
Asinthepriorrecipe,thisexampleusesajava.text.DateFormatobjecttoformatDateStringsforbrowserdisplay.Thedate-relatedHttpSessionmethodsgetCreationTime()andgetLastAccessedTime()returnlongdatatypes,fromwhichjava.util.Dateobjectscanbecreated:
DatecreationTime=newDate(session.getCreationTime());
Thesession'screationtimecanthenbedisplayedusingtheDateFormat'sformat(Date_date)method.
ThenextrecipeshowshowaJSPcantracksessionactivity.
SeeAlso
Recipe11.5andRecipe11.8;Chapter1onweb.xml;Chapter7oftheServletv2.3and2.4specificationsonsessions;thejavax.servlet.http.HttpSessionAPIathttp://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/HttpSession.htmlthesession-trackingsectionsofJavaServletProgrammingbyJasonHunter(O'Reilly)andJavaServerPagesbyHansBergsten(O'Reilly).
Recipe11.6TrackingSessionActivityinJSPs
Problem
Youwanttofindoutasession'screationtimeandlast-accessedtimeusingJSPs.
Solution
UsetheJSTLtogetaccesstotheJSP'sassociatedHttpSessionobject.ThencalltheHttpSession.getCreationTime()andHttpSession.getLastAccessedTime()methodsonthatobject.
Discussion
ItisveryeasytokeeptrackofsessionactivityinaJSP;youjustuseslightlydifferentmethodsandtoolscomparedtothoseusedwithaservlet.Example11-8usestheoutcustomactionfromtheJSTL1.0todisplayinformationaboutthecurrentsession.Chapter24describestheJSTLanditsassociatedELinmoredetail.
Example11-8.TrackingsessionsusingtheJSTL
<%@pagecontentType="text/html"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>ViewSessionJSP</title></head>
<body>
<h2>SessionInfoFromAJSP</h2>
Thesessionid:<c:outvalue="${pageContext.session.id}"/><br><br>
Thesessioncreationtimeasalongvalue:
<c:outvalue="${pageContext.session.creationTime}"/><br><br>
Thelastaccessedtimeasalongvalue:
<c:outvalue="${pageContext.session.lastAccessedTime}"/><br><br>
</body>
</html>
ThisJSPusesataglibdirectivetomakethecustomactionsthatarepartofthecoretaglibraryavailable.Byconvention,theuriattributeforthecoretagsishttp://java.sun.com/jstl/core,andtheprefixisc(youcancreateyourownprefixinthetaglibdirective).WithJSTL1.1,theurivalueishttp://java.sun.com/jsp/jstl/core.TheJSPthenusestheouttagfromtheJSTL'scoretaglibrarytodisplaythecurrentsessionID(thereturnvalueofHttpSession.getId()),thesession'screationtimeasalongtype,andthesession'slast-accessedtime.Figure11-4showsabrowserdisplayofthesevalues.
Figure11-4.ShowingsessioninfoinaJSP
TheoutelementwritesthevalueofitsvalueattributetotheJSP'sresponsestream.However,itistheELthatdoesthefetchingofthevalue.Forexample,thefollowingELexpressiongetsthevalueofthesession'screationtime:
${pageContext.session.creationTime}
ThepageContextreferenceisoneoftheimplicitobjectsthatcanbeaccessedfromtheEL.ThisisequivalenttotheimplicitJSPscriptingobjectofthesamename.
Thewaythecreationtimeisaccessedisdifferentthanamethodcall;youusethedot(.)operatortogetthepageContext'ssessionproperty,theninturnusethedotoperatortoaccessthesessionobject'screationTimeproperty.Sothewholephraselookslikethis:
pageContext.session.creationTime.
Finally,intheEL,allvariableandpropertyvaluesaredereferenced(togettheirvalues)bybracketingthemin${}characters.
TheJSPgetstheothersessionvaluesinthesameway.Forexample,thesession'slast-accessedtime(thelongtypereturnvaluefromthemethodHttpSession.getLastAccessedTime())isreturnedusingthissyntax:
${pageContext.session.lastAccessedTime}
Example11-8displaysthelast-accessedtimeforasessionasalarge,unfriendlynumber.Naturally,thisvalueismoreunderstandabledisplayedasadate.Example11-9showshowtousetheJSTL'scustomformattingactionstoformatadatestring.
Example11-9.Formattingthesessioncreationtimeandlast-accessedtimewiththeJSTL
<%@pagecontentType="text/html"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%@tagliburi="http://java.sun.com/jstl/fmt"prefix="fmt"%>
<html>
<head><title>ViewSessionJSP</title></head>
<body>
<h2>SessionInfoFromAJSP</h2>
ThesessionID:<c:outvalue="${pageContext.session.id}"/>
<h3>SessiondatevaluesformattedasDates</h3>
<jsp:useBeanid="timeValues"class="java.util.Date"/>
<c:settarget="${timeValues}"value=
"${pageContext.session.creationTime}"property="time"/>
Thecreationtime:<fmt:formatDatevalue="${timeValues}"type="both"
dateStyle="medium"/><br><br>
<c:settarget="${timeValues}"value=
"${pageContext.session.lastAccessedTime}"property="time"/>
Thelastaccessedtime:<fmt:formatDatevalue="${timeValues}"type=
"both"dateStyle="short"/>
</body>
</html>
Figure11-5showsthebrowserdisplayforthisJSP.
Figure11-5.Sessiondate/timesformattedusingtheJSTL
ThisJSPtakestwodate-relatedsessionvalues:thedate/timewhenthesessionwascreatedandthelastdate/timewhenarequestassociatedwiththissessionwasmadetothewebapplication.Itdisplaystheirvaluesinthebrowser.Asmentionedpreviously,thesevaluesarereturnedfromtheHttpSessionobjectaslongJavatypes.YouhavetocreateaDateobjectwithitstimepropertysettotheselongvalues.ThenusetheJSTLformattingcustomactionstocreatereadableStringsfromthedates.First,maketheformattingtaglibraryavailabletotheJSPwiththistaglibdirective:
<%@tagliburi="http://java.sun.com/jstl/fmt"prefix="fmt"%>
Thejava.util.DateobjectthatwillbeusedtocreatedatesoutoflongvaluesisgeneratedusingaJSPstandardactioncalledjsp:useBean.Hereistheexample'ssyntax:
<jsp:useBeanid="timeValues"class="java.util.Date"/>
ThislinecreatesanewDateobjectandstorestheobjectinavariablecalledtimeValues,makingitavailablethroughtheELwiththesyntax${timeValues}.TheJSPthenusesthesetcustomactiontosetatimepropertyintheDateobject:
<c:settarget="${timeValues}"value="${pageContext.session.creationTime}"
property="time"/>
Thevalueofset'stargetattributeistheJavaBeanwhosepropertyyouaresetting.Thepropertynameisspecifiedbythesetelement'spropertyattribute.ThevaluethisexpressionsetsthetimepropertytoisthelongtypereturnedfromthisJSTLexpression:
${pageContext.session.creationTime}
Inotherwords,usingthecustomactionthiswayistheequivalentofcallingthejava.util.Date.setTime(longsecs)methodonthetimeValuesDateobject.Thistimevalueisactuallysetanddisplayedtwice,torepresentthecreationtimeandlast-accessedtimeofthesession.Example11-10isthecodechunkthatdoesthesettinganddisplaying,includingthefmt:formatDatecustomaction.
Example11-10.Displayingasession'screationtimeandlast-accessedtime
<c:settarget="${timeValues}"value="${pageContext.session.creationTime}"
property="time"/>
Thecreationtime:<fmt:formatDatevalue="${timeValues}"type="both"
dateStyle="medium"/><br><br>
<c:settarget="${timeValues}"value=
"${pageContext.session.lastAccessedTime}"property="time"/>
Thelastaccessedtime:<fmt:formatDatevalue="${timeValues}"type="both"
dateStyle="short"/>
TheformatDateelementisoneoftheJSTL'sformattingactions,whicharedescribedinChapter24.ThewaytheformatDateactionworksinthisexampleisthatthefollowingcodeisreplacedbytheformatteddatevalue,asin"Jan21,20031:57:39PM":
<fmt:formatDatevalue="${timeValues}"type="both"dateStyle="short"/>
Inordertodisplaytheirdifferences,Example11-10givestwodifferentvalues(mediumandshort)forthedateStyleattribute.
SeeAlso
Recipe11.4oncheckingthevalidityofasession;Chapter1onweb.xml;Chapter7oftheServletv2.3and2.4specificationsonsessions;thejavax.servlet.http.HttpSessionAPIathttp://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/HttpSession.htmlthesession-trackingsectionsofJavaServletProgrammingbyJasonHunter(O'Reilly)andJavaServerPagesbyHansBergsten(O'Reilly).
Recipe11.7UsingURLRewritinginaJSP
Problem
YouwanttomakesurethatURLrewritingisusedinaJSP,incaseanyusersdisablecookiesintheirbrowsers.
Solution
UsetheurlcustomactionintheJSTLtocreateURLsthatautomaticallyincludethesessionIDasaparameter.
Discussion
Itispossiblethatsomeusersofawebapplicationwillconfiguretheirbrowserstodisablecookies.SincecookiesarethedefaultbasisforsessiontrackingwithJSPs,howwilldisablingcookiesaffecttheseusers'experiencewiththewebapplication?Irecommenddesigningallsession-trackingJSPstoaccommodateURLrewriting,sothatthecookie-averseusersdonotcrashandburninyourwebapplication.
OnesolutiontothisproblemistousetheurlcustomactionthatispartoftheJSTL.
TheurlelementautomaticallyinsertsthesessionIDasaparameterwithURLsthatwillbeusedinhref,form,andframesettags,forinstance.Thisallowsthepagesthattheselinkspointto,suchasservletsorJSPs,totracksessionswithoutusingcookies.
OneofthenicethingsaboutusingtheurlelementlikethisisthatitaddsthesessionIDasaparametertotheURLwhennecessary,without
theJSPauthor'sintervention.Example11-11showshowtouseurl.
Example11-11.UsingtheurlcoretagtorewriteURLs
<%@pagecontentType="text/html"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>URLRewriter</title></head>
<body>
<h1>ThispagewilluseURLrewritingifnecessary</h2>
<c:urlvalue="/default.jsp"var="goToDefault"escapeXml="false"/>
Gotothedefault.jsppage<ahref="<c:outvalue="${goToDefault}"/>">here</a>.
</body>
</html>
ThisexampleusesataglibdirectivetomaketheJSTL'scoretaglibraryavailable.Thisdirectivelookslikethis:
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
TheurlelementofthistaglibrarycreatesaURLrepresentingthewebcomponentdefault.jsplocatedonthetoplevelofthewebapplication.TheURLisstoredinagoToDefaultvariableusingtheurlelement'svarattribute.TheescapeXmlattributeissettofalse(itistruebydefault)topreventcharacterssuchasampersandsandanglebracketsfrombeingconvertedtotheircharacterentitycodesintheURL.Theurlelementlookslikethis:
<c:urlvalue="/default.jsp"var="goToDefault"escapeXml="false"/>
TheURLcreatedbythecustomactionisthenusedasthevalueforanhrefattributeinthefollowingmanner:
<ahref="<c:outvalue="${goToDefault}"/>">here</a>
ThiscodeusestheoutcustomactionandanELexpression(${goToDefault})tocreatethehyperlink.Afterthepageisrequested,thereturnedHTMLlookslikethisifcookiesaredisabledinthebrowser:
<ahref="/home/default.jsp;jsessionid=3CAF7CD0A0BFF5076B390CCD24FD8F0D">here</a>
YoumaynoticetwodifferencesbetweentheURLthatwascreatedhere:
<c:urlvalue="/default.jsp"var="goToDefault"escapeXml="false"/>
andtheURLthatwasgeneratedfromtheoutcustomaction:
/home/default.jsp;jsessionid=3CAF7CD0A0BFF5076B390CCD24FD8F0D
First,theurlcustomactionhasautomaticallyaddedthecontextpath(/homeintheexample)asaprefixto/default.jsp.Second,thesessionIDwasaddedtotheURLasapathparameternamedjsessionid,sothatthelinkdestinationcanaccessthesessionIDassociatedwiththisuserandundertakesessiontracking.
Apathparameterbeginswithasemicolonandaname/valuepair,asin;jsessionid=3CAF7CD0A0B.
TheURLthattheJSPcreatesbyusingtheoutelementmayalsohaveadditionalparameters.Example11-12isthesameasthefirstrecipeexample,exceptthatparametershavebeenaddedtotheURLinsidetheurlcustomaction.
Example11-12.Addingparametersusingtheurlcustomaction
<%@pagecontentType="text/html"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>JSPPage</title></head>
<body>
<h1>ThispagewilluseURLrewritingifnecessary</h2>
<c:urlvalue="/default.jsp?n=${param.first}&l=${param.last}"
var="goToDefault"/>
Gotothedefault.jsppage<ahref="<c:outvalue="${goToDefault}"
escapeXml="false"/>">here</a>.
</body>
</html>
TheURLnowlookslikethis:
/default.jsp?n=${param.first}&l=${param.last}
ThisURLusesembeddedELsyntaxtoaccesstworequestparameters,calledfirstandlast.IfcodeusestheELtoaccessaparameternamedfirst,forinstance,thenitusestheparamELimplicitobject,followedbythedotoperator,andthenameoftheparameter,asin${param.first}.SupposetheexampleJSPisrequestedinthefollowingmanner:
http://localhost:8080/home/url_rewrite.jsp?first=Bruce&last=Perry
Theurlelement'svalueattributeresolvestothiscode:
<c:urlvalue="/default.jsp?n=Bruce&l=Perry"var="goToDefault"/>
TheoutcustomactionfurtheralongintheexampleJSPhasitsescapeXmlattributesettofalse.IfescapeXmlisleftwithitsdefaultvalue(true)andtheampersandcharacter(&)isreplacedwithitscharacterentitycode(&),thequerystringintheURLlookslikethis
whentheJSPisexecuted:
<ahref="/home/default.jsp;jsessionid=D37AF592DACABD?n=Bruce&l=Perry">
here</a>
TopreventthisoutcomewhengeneratinglinkedURLswiththeoutelement,makesuretosetout'sescapeXmlattributetofalse.
Table11-1.Specialcharactersandentitycodes
Character Entitycode
< <
> >
& &
' '
" "
MakesuretouserelativeURLsoftheform/default.jspwhenusingURLrewritingwiththeurlelement.URLrewritingwillnottakeplaceifanabsoluteURLisusedinurl'svalueattribute,asinhttp://www.mysite.com/home/default.jsp.
SeeAlso
Recipe11.6ontrackingsessionactivityinJSPs;Recipe11.8onusingURLrewritinginaservlet;theJSPConfigurationsectionoftheJSPv2.0specification;Chapter23ontheJSTL;thesession-trackingsectionsofJavaServerPagesbyHansBergsten(O'Reilly).
Recipe11.8UsingURLRewritinginaServlet
Problem
YouwanttocreateaservletthatusesURLrewritingiftheuserhasdisabledcookiesinhisbrowser.
Solution
UsetheHttpServletResponse.encodeURL(Stringurl)methodtoencodeallURLsthatareusedtolinkwithotherpages.
Discussion
Thejavax.servlet.HttpServletResponseclassincludesaniftymethodthatwillencodeaURLwiththecurrentsessionID,intheeventthattheusermakingtheservletrequesthasdisabledcookies.
Infact,ifyouusetheHttpServletResponse.encodeURL(Stringurl)methodtoencodetheURLsthatareusedinaservlet,thismethodtakescareofURLrewritingifnecessary,andyouwon'thavetoworryaboutwhethercookiesareenabledinusers'browsers.YoumustconscientiouslyencodeeveryURLlinkinvolvedwiththeservletwhenusingthismethod.Example11-13isaservletversionoftheexampleusedinRecipe11.6.
Example11-13.UsingURLrewritinginaservlet
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassUrlRewriteextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
StringcontextPath=request.getContextPath();
StringencodedUrl=response.encodeURL(contextPath+
"/default.jsp");
out.println("<html>");
out.println("<head>");
out.println("<title>URLRewriter</title>");
out.println("</head>");
out.println("<body>");
out.println(
"<h1>ThispagewilluseURLrewritingifnecessary</h2>");
out.println("Gotothedefault.jsppage<ahref=\""+encodedUrl+
"\">here</a>.");
out.println("</body>");
out.println("</html>");
}
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
doGet(request,response);
}
}
Inthepagethatissenttothebrowserwithcookiesdisabled,theURLlookslike:/home/default.jsp;jsessionid=3CAF7CD0A0BFF5076B390CCD24FD8F0D
OneofthedifferencesbetweenusingencodeURLandtheJSPsolutioninRecipe11.7(whichusedtheurlcustomactionfromtheJSTL)isthatthecustomactioninJSTL1.0willautomaticallyprependthecontextpathtotheURL.Ifthecontextpathwas/home,andtheURLwas/default.jsp,thentherewrittenURLwouldlooklike/home/default.jsp;jsessionid=3CAF7CD0A0BFF5076B390CCD24FD8F0D.AutomaticallyaddingthecontextpathinthismannertotheURLisaseparateoperationcomparedwithURLrewriting;itisnotperformedbytheencodeURLmethod.Ifyouwanttoduplicatethisoperationwithaservlet,addthecontextpathtotheURLbeforecallingtheencodeURLmethod,asin:
StringcontextPath=request.getContextPath();
StringencodedUrl=response.encodeURL(contextPath+"/default.jsp")
YoucanalsousetherelatedHttpServletResponse.encodeRedirectURL(Stringurl)methodtoinitiateURLrewritingwithcallstoHttpServletResponse.sendRedirect(Stringurl).TheservletdoGet()methodinExample11-14usesencodeRedirectURLtoensurethatthedestinationURLshaveaccesstothesessionIDoftheredirecteduser.
Example11-14.UsingencodeRedirectURLinaservletdoGetmethod
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throws
ServletException,java.io.IOException{
//redirecttheuserdependingonthevalueofthegoparam
Stringdestination=request.getParameter("go");
StringcontextPath=request.getContextPath();
if(destination==null||destination.equals(""))
thrownewServletException(
"Missingorinvalid'go'parameterin"+
getClass().getName());
if(destination.equals("weather")){
//ensureURLrewriting
response.sendRedirect(
response.encodeRedirectURL(
contextPath+"/weather"));}
if(destination.equals("maps")){
//ensureURLrewriting
response.sendRedirect(
response.encodeRedirectURL(
contextPath+"/maps"));}
}
Theresponse.sendRedirect(Stringurl)methodredirectstherequesttothedestinationrepresentedbyitsurlparameter.TheserversendsanHTTPstatusmessagetotheclient:
HTTP/1.1302MovedTemporarily
Additionally,aLocationresponseheaderissentalongthatprovidestheclientwiththenewURLfortherequestedfile.Ifnecessary,theresponse.encodeRedirectURL(Stringurl)methodaddsthesessionIDtotheredirectdestinationofthisURL.Theexamplegetsthenameofaservletfromthevalueoftherequest'sgoparameter:
Stringdestination=request.getParameter("go");
TheservletthrowsaServletExceptioniftheparameteriseithermissingorisanemptyString.Ifthegoparameterisvalid,theservletredirectstherequesttooneoftwoservlets,withpathsof/weatheror/maps(thecontextpathintheexampleis/home).Ifimplemented
properlyontheserver,thefollowingcodeaddsthesessionIDtotheURLiftherequester'scookiesaredisabled,sothedestinationservletcaninitiatesessiontracking:
response.sendRedirect(response.encodeRedirectURL(contextPath+"/weather"));
SeeAlso
Recipe11.4oncheckingthevalidityofasession;Recipe11.7onusingURLrewritinginaJSP;Chapter1onweb.xml;Chapter7oftheServletv2.3and2.4specificationsonsessions;thejavax.servlet.http.HttpSessionAPIathttp://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/HttpSession.htmlthesession-trackingsectionsofJavaServletProgrammingbyJasonHunter(O'Reilly)andJavaServerPagesbyHansBergsten(O'Reilly).
Recipe11.9UsingaListenertoTracktheSessionLifecycle
Problem
YouwantanobjectthatimplementstheHttpSessionListenerinterfacetorespondwhenasessioniscreatedordestroyed.
Solution
CreatealistenerclassthatimplementstheHttpSessionListenerinterface,andregistertheclassinyourdeploymentdescriptor.
Discussion
TheservletAPIprovidesthejavax.servlet.http.HttpSessionListenerinterfaceforuseinrespondingtosessioncreationordestruction.Aclassthatimplementsthisinterfacecanperformcustombehavioroneither(orboth)ofthesetwoevents.Hereistheprocessforcreatinganddeclaringasessionlistenerforyourwebapplication:
1. CreateaclassthatimplementstheHttpSessionListenerinterface.Thisinterfacedefinestwomethods:sessionCreated()andsessionDestroyed(),eachofwhichacceptasingleHttpSessionEventparameter.
Makesuretheimplementingclasshasazero-argumentconstructor.
PlacethecompiledclassintheWEB-INF/classesdirectoryofyour
webapplication(includinganyofitspackage-relateddirectories);orstoretheclassinaJARlocatedintheWEB-INF/libdirectory.
Declarethelistenerintheweb.xmldeploymentdescriptor.
Restartthewebcontainer(ifnecessary),whichwillinstantiateyourlistenerclassandregisteritasalistenerforallnewsessionsandsessioninvalidationsinthewebapplication.
ObjectsthatareboundtosessionsshouldimplementtheHttpSessionBindingListenerinterface.Thislistenerdoesnothavetobeconfiguredinthedeploymentdescriptor,buttheboundobjectsmustimplementHttpSessionBindingListener,aswellasthevalueBound(),valueUnbound(),andinit()methods.TheHttpSessionActivationListenerisdesignedforsessionsthatmigratebetweenJavaVirtualMachines(JVMs).ObjectsthatareboundtothesesessionsmustimplementHttpSessionActivationListeneranditstwomethods:sessionDidActivate()andsessionWillActivate().
Hereistheweb.xmlentryforourexamplelistenerclass:
<listener>
<listener-class>com.jspservletcookbook.SessionListen</listener-class>
</listener>
TheHttpSessionListenerclassinExample11-15keepsacountoflivesessionsinthewebapplicationandwritesamessagetotheconsolewheneverasessioniscreatedordestroyed.Itwouldbebettertologmessagesusingacomponentsuchaslog4j,whichI'lldiscussinChapter14.
Example11-15.Keepingtrackofsessionactivitywithalistenerclass
packagecom.jspservletcookbook;
importjava.util.Date;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSessionListenimplementsHttpSessionListener{
privateintsessionCount;
publicSessionListen(){
this.sessionCount=0;
}
publicvoidsessionCreated(HttpSessionEventse){
HttpSessionsession=se.getSession();
session.setMaxInactiveInterval(60);
//incrementthesessioncount
sessionCount++;
Stringid=session.getId();
Datenow=newDate();
Stringmessage=newStringBuffer(
"NewSessioncreatedon").
append(now.toString()).append("\nID:").
append(id).append("\n").append("Therearenow").
append(""+sessionCount).append(
"livesessionsintheapplication.").toString();
System.out.println(message);
}
publicvoidsessionDestroyed(HttpSessionEventse){
HttpSessionsession=se.getSession();
Stringid=session.getId();
--sessionCount;//decrementthesessioncountvariable
Stringmessage=newStringBuffer("Sessiondestroyed"+
"\nValueofdestroyedsessionIDis").
append(""+id).append("\n").append(
"Therearenow").append(""+sessionCount).append(
"livesessionsintheapplication.").toString();
System.out.println(message);
}
}
Eachlistenermusthaveazero-argumentconstructor.TheSessionListenclasshasoneinstancevariable,anintthatkeepstrackofthenumberofsessions.InthesessionCreated()method,thecodegetsaccesstothenewsessionbycallingtheHttpSessionEvent.getSession()method.Thesession'stimeoutisthenresetto60seconds,sothecreatinganddestroyingcanbeobservedintheconsolewithoutalotofdelay.
AnHttpSessionListenerclassisnotifiedonlyofrequeststopagesthatcreatenewsessions,suchaswiththerequest.getSession()method.ThislistenerisalsonotifiedifaservletorJSPinvalidatesanexistingsession,aneventthatwilltriggertheclass'ssessionDestroyed()method.IfaservletorJSPisaccessed,butdoesnotdosessiontracking,thenthelistenerisnotnotifiedofthoseactivities;thesameistruewhenthesessionisfurtheraccessedthroughthewebapplicationafteritiscreated,unlessitisexplicitlyinvalidated.
SimilarmessagingandaccesstotheHttpSessionobjecttakesplaceinthesessionDestroyed()method.TheresultingconsoleinFigure11-6showsthatyoucangetinformationabouttheHttpSessionobjectinbothofthelistener'smethods.
Figure11-6.Notificationsofsessioncreationandinvalidation
UsingtheHttpSessionListenerinterface,itispossibletocreateclassesthatmonitorhowmanysessionsarecreatedduringacertainperiodoftime,andhowlongittakesbeforetheyareleftidleandtimeout.
SeeAlso
Chapter14onusinglistenerstologmessages;Recipe11.4oncheckingthevalidityofasession;Chapter1onweb.xml;Chapter7oftheServletv2.3and2.4specificationsonsessions;thejavax.servlet.http.HttpSessionAPIathttp://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/HttpSession.html
Recipe11.10UsingaListenertoMonitorSessionAttributes
Problem
Youwantalistenerclasstobenotifiedwhenasessionattributeisadded,removed,orreplaced.
Solution
CreateaJavaclassthatimplementstheHttpSessionAttributeListenerinterface.Registerthisclassusingthewebapplication'sdeploymentdescriptor.
Discussion
TheHttpSessionAttributeListenerinterfacehasthreemethods:attributeAdded(),attributeRemoved(),andattributeReplaced();allhaveaparameterofthetypeHttpSessionBindingEvent.Thislistenerisnotifiedwhenthesessionsets,removes,orchangesanattribute.Therefore,themethodcallsinthewebapplicationthatcauseanHttpSessionAttributeListenernotificationare:
HttpSession.setAttribute(Stringname,Objectvalue).
HttpSession.removeAttribute(Stringname).
AcalltoHttpSession.setAttribute()whenanattributeof
thesamenameisalreadyboundtothesession.Theoriginalattributeisreplaced,triggeringacalltotheattributeReplaced(HttpSessionBindingEventevent)
method.
Example11-16displaysamessagetotheconsolewhenasessionobjectisbound,includingthevalueoftheobject(whichisaStringinthissimpleexample).Messagesarealsodisplayedwhentheattributeisremovedorreplaced.Tomakethislisteneravailabletotheapplication:
1. Givetheclassazero-argumentconstructor.
Addtheclasstothewebapplication'sWEB-INF/classesorlibdirectory(whenit'sinaJAR).
Declarethelistenerinthedeploymentdescriptor.
Restartthewebcontainer(ifnecessary)soitcaninstantiatethelistener.
Example11-16.Listeningforsessionobjectbindingorunbinding
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSessionAttribListenimplementsHttpSessionAttributeListener{
//CreatesnewSessionAttribListen
publicSessionAttribListen(){
System.out.println(getClass().getName());
}
publicvoidattributeAdded(HttpSessionBindingEventse){
HttpSessionsession=se.getSession();
Stringid=session.getId();
Stringname=se.getName();
Stringvalue=(String)se.getValue();
Stringsource=se.getSource().getClass().getName();
Stringmessage=newStringBuffer(
"Attributeboundtosessionin").append(source).
append("\nTheattributename:").append(name).
append("\n").append("Theattributevalue:").
append(value).append("\n").
append("ThesessionID:").
append(id).toString();
System.out.println(message);
}
publicvoidattributeRemoved(HttpSessionBindingEventse){
HttpSessionsession=se.getSession();
Stringid=session.getId();
Stringname=se.getName();
if(name==null)
name="Unknown";
Stringvalue=(String)se.getValue();
Stringsource=se.getSource().getClass().getName();
Stringmessage=newStringBuffer(
"Attributeunboundfromsessionin").append(source).
append("\nTheattributename:").append(name).
append("\n").append("Theattributevalue:").
append(value).append("\n").append(
"ThesessionID:").append(id).toString();
System.out.println(message);
}
publicvoidattributeReplaced(HttpSessionBindingEventse){
Stringsource=se.getSource().getClass().getName();
Stringmessage=newStringBuffer(
"Attributereplacedinsession").
append(source).toString();
System.out.println(message);
}
}
Whenattributesareadded,replaced,andremovedfromasessioninthewebapplication,thisclassprintsinformationabouttheattributeandthesessiontothewebcontainer'sconsole.TheHttpSessiontypethatbindstheattributecanbeaccessedbycallingtheHttpSessionBindingEventclass'sgetSession()method.Inallthreeofthelistener'smethods,youcangettheIDofthesessionassociatedwiththeattribute,aswellastheattribute'snameandvalue.Insidethelistenerclass'sconstructorisalineofcodethatprintsthelistenerclassnametotheconsolewhenitisinstantiated:
System.out.println(getClass().getName());
Thismessageindicatestothedeveloperthatthelistenerisproperly
referencedinweb.xml,andthatthewebcontainerhascreatedaninstanceofthelistener.Finally,thislistenerclassprintsamessagetotheconsoleaboutthesessionclassthatisthesourceoftheevent.Thelistenerusesthejava.util.EventObject.getSource()method(whichisinheritedbytheHttpSessionBindingEventobject)togetareferencetothesourceofthesession-bindingevent:
Stringsource=se.getSource().getClass().getName();
ThesevariableistheHttpSessionBindingEventobject.HereistheinformationthatisprintedtotheTomcatconsole:
Attributeboundtosessioninorg.apache.catalina.session.StandardSession
Theattributename:session-attribute
Theattributevalue:Hello
ThesessionID:9ED2C34964778265A34F7AB0DEA4B884
Attributereplacedinsessionorg.apache.catalina.session.StandardSession
Attributeunboundfromsessioninorg.apache.catalina.session.StandardSession
Theattributename:session-attribute
Theattributevalue:Hellothere.
ThesessionID:9ED2C34964778265A34F7AB0DEA4B884
ThelistenerallowsyoutogetthesessionID,aswellasthenameandvalueofthesessionattribute,duringtheattribute'sremovalfromthesession.TheHttpSessionBindingEvent.getValue()methodreturnsthevalueoftheattributeasajava.lang.Object.Therefore,ifyouwantaccesstotheattributeinthelistener,thenyouwouldhavetocasttheObjecttypetoitsappropriatetypeduringitsaddition,removal,orreplacement.Forexample,imaginethatyouhavestoredajava.util.Mapinasession.YouwanttochecktheMapcontentsinthelistener'sattributeRemovedmethod.IfthevariablebeisoftypeHttpSessionBindingEvent,thenthiscodechecksthereturntypeofbe.getValue():
java.util.Mapmap=null;
Objectvalue=null;
if((value=be.getValue())instanceofjava.util.Map){
map=(java.util.Map)value;
System.out.println("HashMapvalue:"+map.get("key"));
}
Thismethodreturnsthevalueofthesession-boundobjectthat'sbeingremoved.IfthereturntypeisaMap,thelocalvariablevalueiscasttoajava.util.Map,thentheget()methodiscalledonthatMap(giventhattheMapinstancecontainsakeycalled"key").
SeeAlso
Chapter14onusinglistenerstologmessages;Recipe11.4oncheckingthevalidityofasession;Recipe11.9onusingalistenertotracksessionlifecycle;Chapter1onweb.xml;Chapter7oftheServletv2.3and2.4specificationsonsessions;thejavax.servlet.http.HttpSessionAPIathttp://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/HttpSession.html
Recipe11.11UsingaFiltertoMonitorSessionAttributes
Problem
Youwanttouseafiltertocheckasessionattributepriortotherequestreachingaservlet.
Solution
CreateaJavaclassthatimplementsjavax.servlet.Filter,writesession-relatedcodeintheclass'sdoFilter()method,thenconfigurethefilterinyourdeploymentdescriptor.
Discussion
Filters,astheirnamesuggests,aresemipermeablebarriersthroughwhichrequeststoyourwebapplicationmustpassbeforetheyreachservlets,JSPs,orevenstaticcontent.FiltersaretechnicallyJavaclassesthatimplementthejavax.servlet.Filterinterface.AfiltercanhavealookattheServletRequestandServletResponseobjectsbeforetheseobjectsfindtheirwaytoaservlet'sservicemethods(whichincludeservice(),doGet(),anddoPost()).Filterscaninitiateauthentication,logging,encryption,databaseactions,caching,andjustaboutanyothertaskthatpassesthroughrequestandresponseobjects.
Filtersareconfiguredinweb.xml.InExample11-18,afilterchecksalogged-inHttpSessionattribute,andlogsitsactivitiesbycallingtheServletContextobject'slog()method.Thisfilterismappedtoaservletregisteredinweb.xmlasMyServlet.Anyrequeststothe
MyServletservletcausetheSessionFilter.doFilter()methodtobecalled.Example11-17showstherelevantentriesinweb.xml.
Example11-17.Configuringafilterinweb.xml
<!--thebeginningofweb.xmlgoeshere-->
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>com.jspservletcookbook.SessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<servlet-name>MyServlet</servlet-name>
</filter-mapping>
<!--morefiltersorlistenerclassesaddedhere-->
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.jspservletcookbook.MyServlet</servlet-class>
</servlet>
<!--deploymentdescriptorcontinues...-->
Thefilterelementspecifiesthefilter'sregisterednameanditsfullyqualifiedJavaclass.YoupackagethefilterclasswiththerestofthewebapplicationbyplacingtheclassinWEB-INF/classesorinaJARfileinWEB-INF/lib.Thefilter-mappingelementmapsthefiltertotheservletregisteredinthedeploymentdescriptorasMyServlet.FilterscanalsobemappedtoURLpatterns(Chapter20explainsthissyntaxindetail).Example11-18isthesourcecodeforcom.jspservletcookbook.SessionFilter.
Example11-18.Afilterthatsnoopsonsessioninformation
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSessionFilterimplementsFilter{
privateFilterConfigconfig;
//CreatesnewSessionFilter
publicSessionFilter(){}
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
System.out.println("Instancecreatedof"+getClass().getName());
this.config=filterConfig;
}
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsjava.io.IOException,ServletException{
HttpSessionsession=((HttpServletRequest)request).getSession();
ServletContextcontext=config.getServletContext();
/*usetheServletContext.logmethodtolog
filtermessages*/
context.log("doFiltercalledin:"+config.getFilterName()+
"on"+(newjava.util.Date()));
//logthesessionID
context.log("sessionID:"+session.getId());
//Findoutwhetherthelogged-insessionattributeisset
Stringlogged=(String)session.getAttribute("logged-in");
if(logged==null)
session.setAttribute("logged-in","no");
//logamessageaboutthelog-instatus
context.log("log-instatus:"+
(String)session.getAttribute("logged-in"));
context.log("");
chain.doFilter(request,response);
}
publicvoiddestroy(){
/*calledbeforetheFilterinstanceisremoved
fromservicebythewebcontainer*/
}
}
Everyfilterhastohaveazero-argumentconstructor,justlikelistenerclasses.
Theinit()methoddisplaysaconsolemessagewhenitsinstanceiscreatedbythewebcontainer.Thejavax.servlet.FilterConfigobjectisusedtogettheServletContextobjectforthisfilter(bycallingFilterConfig.getServletContext()).TheServletContext.log()methodisusedtologmessagesfromthefilter.Thesemessagescanthenbereadintheserverlogs.InTomcat,lookinthe<Tomcat-install-directory>/logsdirectoryforlogfileswithnamessuchaslocalhost_home_log.2003-01-24.txt.Hereisanexampleofthelogentriesforthisfilter:
2003-01-2411:56:09doFiltercalledin:SessionFilteronFriJan2411:56:09EST2003
2003-01-2411:56:09sessionID:E04DE93D9B88A974ED2350BCF7945F34
2003-01-2411:56:09log-instatus:no
Thefiltergetsaccesstothesessionwiththiscode:
HttpSessionsession=((HttpServletRequest)request).getSession();
SincethedoFilter()methodhasaServletRequestparametertype,andnotaHttpServletRequesttype,therequestparameterhastobecasttothelattertypesothatthecodecancalltherequest.getSession()method.
BewareofdoingthisblindlyinenvironmentswhereyouarenotpositivethatallservletsareHttpServlets.Ifyouaren'tsure,asimpleclasscheckbeforecastingcansolvethisproblem.
Oncethefilterhasaccesstothesessionobject,itlooksforacertainsessionattribute(logged-in).Ifsession.getAttribute("logged-in")returnsnull,thisattributeisaddedtothesessionwiththevalue"no".Thecodethencallschain.doFilter(request,response)insideofthefilter'sdoFilter()method.
ThismethodcallontheFilterChainobjectensuresthattherequestandresponsearepassedalongtothenextfilteronthechain,or,intheabsenceofanymoremappedfilters,tothetargetedwebresource.Example11-19showsthedoGet()methodoftheMyServletservletthatthefilterinExample11-18ismappedto.
Example11-19.doGetmethodofaservlettowhichafilterismapped
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
HttpSessionsession=request.getSession();
Stringlogged=(String)session.getAttribute("logged-in");
out.println("<html>");
out.println("<head>");
out.println("<title>FilterServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h2>SessionLoggedinInfo</h2>");
out.println("loggedin:"+logged+"<br><br>");
out.println("</body>");
out.println("</html>");
}
Thisservletchecksthelogged-insessionattributeanddisplaysitsvalue,asshowninFigure11-7.
Afilterismappedtoaservlet'sregisterednamelikethis:
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<servlet-name>MyServlet</servlet-name>
</filter-mapping>
Therequestsforthisservletwillnotpassthroughthemappedfilterfirst,however,iftheservletisrequestedwithan"invoker"-styleURLoftheformhttp://localhost:8080/servlet/com.jspservletcookbook.MyServlet.Ifthiscausesproblemsforthewebapplication,considerdisablingoroverridingtheURLmappingof/servlet/*inyourwebapplication.Recipe3.6describeshowtodothis.
Figure11-7.Checkingasessionobjectafterafilterhasalteredit
AfiltercantakeanumberofactionswithasessionobjectbeforeitreachesaservletorJSPthatdoessessiontracking,suchasadd,remove,orchangesessionattributes.Itcanalsoalterthesession'stimeoutperiod(withtheHttpSession.setMaxInactiveInterval(intseconds)method)basedonanattributeofthesessionorrequest.
SeeAlso
Chapter19onusingfilters;Recipe11.4oncheckingthevalidityofasession;Chapter1onweb.xml;Chapter7oftheServletv2.3and2.4specificationsonsessions;thejavax.servlet.http.HttpSessionAPIathttp://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/HttpSession.htmlChapter1onweb.xml;Chapter6oftheServletv2.3and2.4specificationsonfiltering.
Chapter12.IntegratingJavaScriptwithServletsandJSPs
Introduction
Recipe12.1.IncludingJavaScriptModulesinaServlet
Recipe12.2.IncludingJavaScriptModulesinaJSP
Recipe12.3.CreatingaNewWindowwithJavaScriptinaServlet
Recipe12.4.CreatingaNewWindowwithJavaScriptinaJSP
Recipe12.5.UsingJavaScripttoValidateFormValuesinaServlet
Recipe12.6.UsingJavaScripttoValidateFormValuesinaJSP
Introduction
JavaScriptisascriptingsystemforwebpages,standaloneapplications,andservers.NetscapeCorporationinventedJavaScript,whichhasbecomesuchapopularandusefulprogrammingtoolthatallmajorbrowsersnowsupportit.UnliketheJavacodeshowninthisbook,JavaScriptismainlyexecutedinthewebbrowserasaclient-sidescriptingsystem,ratherthanontheserver.
MostbusywebsitesuseJavaScriptfordynamicbehavior,suchasvalidatingforminputorcreatingnewbrowserwindows(muchtothechagrinofusers,whoareoftenoverwhelmedbyirresponsibleanddynamicallygeneratedpopups!).Justchoose"ViewSource"fromthebrowsermenubarforatypicalwebpage,andoftenthefirsttextitemsyou'llseedisplayedareendlesslinesofJavaScript.JavaScriptisusedforadvancedtaskssuchascontrollingoranimatingbrowsershapes(dynamicHTML),creatingflyingobjects,andinitializingthebehaviorofembeddedvideos.
DevelopersconvertingstaticwebpagestoJSPsorservletsmayhavetointegrateexistingJavaScriptcodeintotheirJavasourcecode.Thisiswhattheupcomingrecipesareallabout.
JavaScriptguidesareavailablefromhttp://devedge.netscape.com/.
Recipe12.1IncludingJavaScriptModulesinaServlet
Problem
YouwanttoimportamoduleorfilecontainingJavaScriptcodesothattheJavaScriptcanbeincludedintheservlet'sHTMLoutput.
Solution
Usethejavax.servlet.RequestDispatch.include()methodtoimporttheneededJavaScriptintoyourpage.
Discussion
AnefficientmethodforhandlingJavaScriptthroughoutawebprojectistostoretheJavaScriptcodeinseparatefilesormodules.ServletsthatrequiretheJavaScriptfunctionscanthenimporttheJavaScriptmodules.YouwouldnotstoreyourJavaclassfileswilly-nillyalloverthecomputer'sfilesystemwithoutanorganizationthatmirrorsthecode'spurpose.NorshouldyouorganizeyourJavaScriptinanythingbutwell-definedmodules.
TheJavaScriptisincludedintheservlet'sHTMLoutputwithscripttagsandexecutedinthebrowserwhenneeded.Example12-1showsamoduleofJavaScriptcodenamedfunctions.js.Thismoduleisstoredinthewebapplication'sWEB-INF/javascriptdirectory.
AsensibleplacetostoreJavaScriptmodulesisintheirowndirectory,sothattheyareeasytolocateanddonotclutterupthetop-leveldirectoryofthewebapplication.TheJavaScriptdirectorycanbeasub-directoryofWEB-INF,asin
thisrecipe.
Example12-1.AJavaScriptmodule
<scriptlanguage="JavaScript">
functionCheckEmail(email)
{
varfirstchunk,indx,secondchunk
if(email==""){
alert("Pleasemakesureyouhaveenteredavalid"+
"emailbeforesubmittingtheinfo.")
returnfalse
}
//getthezero-basedindexofthe"@"character
indx=email.indexOf("@")
//ifthestringdoesnotcontainan@,thenreturnfalse
if(indx==-1){
alert("Pleasemakesureyouhaveenteredavalid"+
"emailbeforesubmittingtheinfo.")
returnfalse
}
//ifthefirstpartofemailis<twocharsandthyesecondpartis<sevenchars
//(arbitrarybutworkablecriteria),rejecttheinputaddress
firstchunk=email.substr(0,indx)//uptobutnotincludingthe"@"
//startatcharfollowingthe"@"andincludeuptoendofemailaddr
secondchunk=email.substr(indx+1)
//ifthepartfollowingthe"@"doesnotincludeaperiod"."then
//alsoreturnfalse
if((firstchunk.length<2)||(secondchunk.length<7)||
(secondchunk.indexOf(".")==-1)){
alert("Pleasemakesureyouhaveenteredavalid"+
"emailbeforesubmittingtheinfo.")
returnfalse
}
//theemailwasokay;atleastithada@,morethanoneusernamechars,
//morethansixcharsafterthe"@",andthesubstringafterthe"@"
//containeda"."char
returntrue
}//CheckEmail
functionCreateWindow(uri){
varnewWin=
window.open(uri,'newwin1',
'width=500,height=400,resizable,'+
'scrollable,scrollbars=yes');
newWin.focus();
}
</script>
ThemoduleinExample12-1containsascriptblockwithtwo
JavaScriptfunctiondefinitions.ThefunctionCheckEmailensuresthattheemailaddressauserhastypedintoanHTMLformcontainsatleastan@character,twocharactersprecedingthe@andsevencharactersafterthatcharacter,andthatthecharactersafterthe@containaperiodcharacter(.).TheCreateWindowfunctioncreatesanewbrowserwindowwiththesuppliedURI.
Example12-2showsaservletthatimportsthisJavaScriptfileusingthejavax.servlet.RequestDispatcher.include()method.
Example12-2.AservletincludesaJavaScriptfile
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassModuleServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throws
ServletException,java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head>");
RequestDispatcherdispatcher=request.getRequestDispatcher(
"/WEB-INF/javascript/functions.js");
dispatcher.include(request,response);
out.println("<title>ClientForms</title></head><body>");
out.println("<h2>EnterYourNameandEmail</h2>");
out.println("<formaction=
\"/home/displayHeaders.jsp\"name=\"entryForm\"onSubmit=
\"returnCheckEmail(this.email.value)\">");
out.println("<tableborder=\"0\"><tr><tdvalign=\"top\">");
out.println(
"Firstandlastname:</td><tdvalign=\"top\"><inputtype=
\"text\"name=\"name\"size=\"20\"></td></tr>");
out.println("<tr><tdvalign=\"top\">");
out.println("Email:</td>
<tdvalign=\"top\"><inputtype=\"text\"name=
\"email\"size=\"20\"></td>");
out.println("<tr><tdvalign=\"top\"><inputtype=
\"submit\"value=\"Submit\"></td>");
out.println("</tr></table></form>");
out.println("</body></html>");
}//doGet
}
TheservletinExample12-2usesaRequestDispatchertoincludethecodecontainedinfunctions.jswithintheHTMLheadtaggeneratedbytheservlet.ThegeneratedpageincludesanHTMLformtag.WhenthepageuserclickstheSubmitbutton,theformtag'sonSubmiteventhandlercheckstheemailaddressthattheusertypedintotheformusingtheimportedJavaScriptCheckEmailfunction.Thisfunctionreturnsfalse,whichcancelstheformsubmissioniftheemailaddressdoesnotmeetthesimplecriteriaspecifiedbythefunction.
Figure12-1showswhatthewebpagelookslikewhentheuserhasenteredanemailaddressintotheform.
Figure12-1.AservletgeneratesawebpagecontainingJavaScript
Userscanalsousethebuilt-insrcattributeoftheHTMLscripttagtoimportaJavaScriptmodule,asin:
<scriptsrc="functions.js">
SeeAlso
TheNetscapeDevEdgesiteathttp://devedge.netscape.com/;Recipe12.2,Recipe12.4,andRecipe12.6onusingJavaScriptwithJSPs;Recipe12.3onusingJavaScriptwithservletsforcreatingnewbrowserwindows;Recipe12.5onvalidatingformvalueswithaservletandJavaScript;Recipe18.3onusingafilterwithHTTPrequests.
Recipe12.2IncludingJavaScriptModulesinaJSP
Problem
YouwanttoincludeamoduleorfilecontainingJavaScriptcodewithinaJSPpage'soutput.
Solution
Usethec:importJSTLcoretag.
Discussion
ThepreviousrecipedescribedhowtoincludeafilecontainingJavaScript(Example12-1)intoaservlet'sHTMLinput.ItisveryeasytoaccomplishthesametaskinaJSP,suchasbyusingtheimportMod.jspfileshowninExample12-3.ThisJSPusestheJSTLcoretagc:importtoincludeafilenamedfunctions.js.Thefunctions.jsmodulecontainsascripttagwithtwoJavaScriptfunctiondefinitions(Example12-1inRecipe12.1).TheHTMLgeneratedbytheJSPshowsthatthec:importactionpositionedthescripttagwithintheJSP'sheadtag.TheJSPgeneratestheHTMLformshownpreviouslyinFigure12-1.
Example12-3.UsingtheJSTLc:importtagtoimportJavaScript
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head>
<c:importurl="/WEB-INF/javascript/functions.js"/>
<title>ClientForms</title></head><body>
<h2>EnterYourNameandEmail</h2>
<formaction="/home/displayHeaders.jsp"name="entryForm"
onSubmit="returnCheckEmail(this.email.value)">
<tableborder="0"><tr><tdvalign="top">
Firstandlastname:</td><tdvalign="top"><inputtype="text"name="name"size="20"></
td></tr>
<tr><tdvalign="top">
Email:</td><tdvalign="top"><inputtype="text"name="email"size="20"></td></tr>
<tr><tdvalign="top"><inputtype="submit"value="Submit"></td>
</tr></table>
</form>
</body></html>
WhentheusersubmitstheHTMLform,heractionisinterceptedbytheformtag'sonSubmiteventhandler,whichdoesabasicsyntaxcheckontheemailaddresstheusertypedintotheform.Theformsubmit,targetedtoa/home/displayHeaders.jsppage,iscancelledifthesubmittedemailaddresshasthewrongsyntax.
TheJavaScriptcodethis.email.valuereturnstheStringthattheusertypedintothetextfieldnamedemail.Thekeywordthisreferstotheformobject,whichcontainstheeventhandleronSubmit.TheJavaScriptcodeisaparameterofthiseventhandler.
SeeAlso
TheNetscapeDevEdgesiteathttp://devedge.netscape.com/;Recipe12.4onusingJavaScripttocreateanewwindowinaJSP;Recipe12.6onusingJavaScripttovalidateforminputinaJSP;Recipe12.3onusingJavaScriptwithservletsforcreatingnewbrowserwindows;Recipe12.5onvalidatingformvalueswithaservletandJavaScript;Recipe18.3onusingafilterwithHTTPrequests.
Recipe12.3CreatingaNewWindowwithJavaScriptinaServlet
Problem
YouwantaservlettocontainJavaScriptthatcangenerateanewbrowserwindow.
Solution
Useajavax.servlet.RequestDispatchertoincludetheJavaScriptfunctionintheservlet.TheJavaScriptfunctioncallstheJavaScriptwindowobject'sopenmethod.
Discussion
Thisrecipeusesthesameimportedmoduleasthefirsttworecipes,butthistimetheservletusesthesecondfunctiondefinition(CreateWindow)ratherthanthefirst.Example12-4generatesanHTMLbuttonwidget.Whentheuserclicksthebutton,JavaScriptgeneratesasmallwindow(sometimesreferredtoasawindoid,orpopup).TheservletdynamicallyretrievestheURLforloadingintothenewwindowfromaservletinitparameter,whichissomethingyoucannotdowithastaticHTMLpage.
Example12-4.AservletthatloadsJavaScriptforcreatingawindow
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassWindowServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throws
ServletException,java.io.IOException{
//URLforthepop-upwindowisconfigured
Stringurl=getInitParameter("popup-url");
//justincasetheinitParameterismisconfigured
if(url==null||url.equals(""))
url="/displayHeaders.jsp";
//addthecontextpathasaprefixtotheURL,asin/home
url=request.getContextPath()+url;
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head>");
RequestDispatcherdispatcher=request.getRequestDispatcher(
"/WEB-INF/javascript/functions.js");
dispatcher.include(request,response);
out.println("<title>HelpPage</title></head><body>");
out.println("<h2>CookieInfo</h2>");
out.println("<formaction=\"\"onSubmit=\"returnfalse\">");
out.println("<tableborder=\"0\"><tr><tdvalign=\"top\">");
out.println(
"Clickonthebuttontogetmoreinfooncookies:</td>");
out.println("<tdvalign=\"top\">");
out.println("<inputtype=\"button\"name=\"button1\""+
"value=\"MoreInfo\"onClick=\"CreateWindow('"+url+
"')\"></td></tr>");
out.println("</table></form>");
out.println("</body></html>");
}//enddoGet
}
Thisservletassumessomeconfigurationstepshavebeentakenintheapplication'sdeploymentdescriptor.Thisconfigurationincludesaninit-paramthatspecifiestheURLforloadingintothenewwindow.TheurlvariableistheCreateWindowfunction'sparameter(seeExample12-1foradefinitionoftheJavaScriptfunctions).TheservletgeneratestheHTMLanddynamicallyprovidestheURLforloadingintothenewwindow.HereistheHTMLbuttondefinitionintheservlet'soutput:
<inputtype="button"name="button1"value="MoreInfo"
onClick="CreateWindow('home/cookieReader.jsp')">
Iftheapplicationisdynamicallyreloadable(thewebcontainermonitorsthedeploymentdescriptorforanychangesandreloadsthecontextifthefileisaltered),thenthedevelopercanchangethevalueoftheservletinit-paraminthedeploymentdescriptor.Theservletpop-upwindowthenloadsthenewURLwithoutrecompilingtheservletorstoppingtheserver.
Hereistheconfigurationforthisservletinweb.xml:
<servlet>
<servlet-name>windowservlet</servlet-name>
<servlet-class>com.jspservletcookbook.WindowServlet</servlet-class>
<init-param>
<param-name>popup-url</param-name>
<param-value>/cookieReader.jsp</param-value>
</init-param>
</servlet>
TheservletloadsthedefinitionfortheJavaScriptfunctionCreateWindowwiththiscode:
RequestDispatcherdispatcher=request.getRequestDispatcher(
"/WEB-INF/javascript/functions.js");
IntheHTMLcodetheservletgenerates,thescripttagcontainingtheJavaScriptcodeappearswithintheHTMLheadtag.Whentheuserclickstheformbuttonontheservlet-generatedwebpage,anewwindowiscreatedandtheURLspecifiedbytheinit-paramelementinweb.xml(cookieReader.jsp)isloaded.Figure12-2showstheservletoutput.Figure12-3showsthepop-upwindow.
Figure12-2.Aservletthatcreatesapop-upwindow
Figure12-3.ThenewwindowloadsaURLvaluefromaservletinit-param
SeeAlso
TheNetscapeDevEdgesiteathttp://devedge.netscape.com/;Recipe12.2,Recipe12.4,andRecipe12.6onusingJavaScriptwithJSPs;Recipe12.5onvalidatingformvalueswithaservletandJavaScript;Recipe18.3onusingafilterwithHTTPrequests.
Recipe12.4CreatingaNewWindowwithJavaScriptinaJSP
Problem
YouwanttouseJavaScriptinaJSPtocreateanewbrowserwindow.
Solution
Usethec:importJSTLtagtoimporttheJavaScriptcodeintotheJSP.ThenusetheinitParamJSTLimplicitobjecttodynamicallyprovidetheURLforaJavaScript-generatedwindow.
Discussion
TheJSPinExample12-5(windowJ.jsp)usestheJSTL'sc:importcoretagtoimporttheJavaScriptfunctiondefinitionforcreatinganewwindow.TheJSPthencallstheJavaScriptfunction(CreateWindow)intheonClickeventhandlerforawebpagebutton.TheCreateWindowfunctionloadstheURLspecifiedinitsparameterintothenewbrowserwindow.Example12-5usesthec:outcoretagandELsyntaxtodynamicallyacquiretheURLfortheJavaScriptwindowfromacontextparameter.Thec:outtaglookslikethis:
<c:outvalue=
"${pageContext.request.contextPath}${initParam[\"jsp-url\"]}"/>
ThevalueattributespecifiestwoELexpressions.ThefirstoneprovidestheJSP'scontextpath,whilethesecondgivesthevalueofthecontext-paramelementjsp-url.ThefullURLspecifiedbythese
concatenatedELexpressionsis/home/cookieReader.jsp.
Example12-5.UsingtheJSTLtoimportJavaScriptintoaJSP
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head>
<c:importurl="/WEB-INF/javascript/functions.js"/>
<title>HelpPage</title></head><body>
<h2>CookieInfo</h2>
<formaction=""onSubmit="returnfalse">
<tableborder="0"><tr><tdvalign="top">
Clickonthebuttontogetmoreinfooncookies:</td>
<tdvalign="top">
<inputtype="button"name="button1"value=
"MoreInfo"onClick=
"CreateWindow('<c:outvalue=
"${pageContext.request.contextPath}${initParam[\"jsp-url\"]}"/>')">
</td></tr>
</table></form>
</body></html>
ThisJSPusesthefollowingcontext-paramelementinweb.xml:
<context-param>
<param-name>jsp-url</param-name>
<param-value>/cookieReader.jsp</param-value>
</context-param>
TheELimplicitobjectinitParamevaluatestoajava.util.Map
containingthenamesandvaluesofanycontext-paramelementsconfiguredforthewebapplication.AnimplicitobjectisavariablethattheJSTLautomaticallymakesavailabletoyourJSPcode.
Example12-5usestheELsyntaxinitParam[\"jsp-url\"],asopposedtoinitParam.jsp-url,inordertoreturntheintendedvalueinTomcat5(alphaversionasofthiswriting).Thecode'spurposeistoescapethehyphencharacter(-)in"jsp-url."
SeeAlso
TheNetscapeDevEdgesiteathttp://devedge.netscape.com/;Recipe12.2andRecipe12.6onusingJavaScriptwithJSPstoimportJavaScriptandvalidateforminput;Recipe12.3oncreatingnewbrowserwindowswithservletsandJavaScript;Recipe12.5onvalidatingformvalueswithaservletandJavaScript;Recipe18.3onusingafilterwithHTTPrequests.
Recipe12.5UsingJavaScripttoValidateFormValuesinaServlet
Problem
YouwanttovalidateforminputvaluesusingJavaScriptinaJSP.
Solution
Useajavax.servlet.RequestDispatchertoincludethevalidatingJavaScriptintheservlet.ThencallthevalidatingJavaScriptfunctionintheform'sonSubmiteventhandler.
Discussion
Example12-6isaJavaScriptmodulenamedvalidate.js.ThisfileshouldbelocatedinWEB-INF/javascript/validate.js.Thefilecontainsascripttagthatcontainsonefunctiondefinition:validate.ThisJavaScriptfunctioniteratesthroughtheformelements(suchasinputtagswhosetypeattributeistextinotherwords,textformfields)todetermineifanyofthemhavebeenleftblank.Theparameterforthevalidatefunctionisaformobject.
Iftheuserhasleftthefieldsempty,thisfunctiondisplaysanalertwindowandthencancelstheformsubmit.Amorerealisticvalidationfunctionmightinvolveagreaterdegreeofcomplexbusinesslogic,butIamkeepingthisexamplesimpleinordertodemonstratethemechanicsofincludingthefunctioninaservlet.
Example12-6.AJavaScriptmodulenamedvalidate.jsforvalidatingforminput
<scriptlanguage="JavaScript">
functionvalidate(form1)
{
for(i=0;i<form1.length;i++){
if((form1.elements[i].value=="")){
alert("Youmustprovideavalueforthefieldnamed:"+
form1.elements[i].name)
returnfalse
}
}
returntrue
}
</script>
TheservletinExample12-7includesthevalidate.jsfileusingaRequestDispatcher.TheRequestDispatcherpositionstheJavaScriptscripttagwithinanHTMLheadtagintheservlet'soutput.Theservletpage'sformtaghasanattributethatiscomposedofthecontextpath(thereturnvalueofrequest.getContextPath())concatenatedwiththe/displayHeaders.jspJSPfile.Iftheformfieldsarefilledoutproperly,thebrowsersubmitstheformtotheJSPpage(/home/displayHeaders.jsp).
Finally,theform'sonSubmiteventhandlercallstheincludedJavaScriptfunctionvalidate,passinginthethisJavaScriptkeyword.Thethisparameterevaluatestotheformobject.Iftheuserfailstofilloutthenameandemailfields,thevalidatefunctioncancelsthebrowser'ssubmissionoftheformbyreturningfalse.
Example12-7.ImportingJavaScriptinaservlettovalidateformvalues
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassFormServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head>");
RequestDispatcherdispatcher=request.getRequestDispatcher(
"/WEB-INF/javascript/validate.js");
dispatcher.include(request,response);
out.println("<title>HelpPage</title></head><body>");
out.println("<h2>Pleasesubmityourinformation</h2>");
out.println(
"<formaction=\""+request.getContextPath()+
"/displayHeaders.jsp\"onSubmit=\"returnvalidate(this)\">");
out.println("<tableborder=\"0\"><tr><tdvalign=\"top\">");
out.println("Yourname:</td><tdvalign=\"top\">");
out.println("<inputtype=\"text\"name=\"username\"size=\"20\">");
out.println("</td></tr><tr><tdvalign=\"top\">");
out.println("Youremail:</td><tdvalign=\"top\">");
out.println("<inputtype=\"text\"name=\"email\"size=\"20\">");
out.println("</td></tr><tr><tdvalign=\"top\">");
out.println(
"<inputtype=\"submit\"value=\"SubmitInfo\"></td></tr>");
out.println("</table></form>");
out.println("</body></html>");
}//doGet
}
Figure12-4showsthebrowserpagecontainingtheform.Figure12-5showsthealertwindowgeneratedbytheJavaScriptfunction.
Figure12-4.TheservletoutputforanHTMLform
Figure12-5.TheincludedJavaScriptvalidatefunctionproducesanalertwindow
Anotheroptionforvalidatingforminputistouseafiltertocheck
parametervalues,andthenreturntheusertotheformpageoranewpageiftheinputcontainsanerror.DevelopersmightpreferthisoptionbecauseafilterallowsyoutouseJavacodetoparsetheparametervaluesandgivesyouagreatdealofcontroloverthecustomizationoftheresponsepage,inthecaseofaforminputerror.Recipe18.3describeshowtouseafilterwithaservlettodealwithclientrequests.
SeeAlso
TheNetscapeDevEdgesiteathttp://devedge.netscape.com/;Recipe12.2andRecipe12.6onusingJavaScriptwithJSPstoimportJavaScriptandvalidateforminput;Recipe12.3oncreatingnewbrowserwindowswithservletsandJavaScript;Recipe12.5onvalidatingformvalueswithaservletandJavaScript;Recipe18.3onusingafilterwithHTTPrequests.
Recipe12.6UsingJavaScripttoValidateFormValuesinaJSP
Problem
YouwanttoimportJavaScriptintoaJSPtovalidateHTMLformvalues.
Solution
Usethec:importJSTLcoretagtoimporttheJavaScriptfunctiondefinitions.ThenvalidatetheHTMLforminputbyusingtheformtag'sonSubmiteventhandler.
Discussion
TheJSPinExample12-8usestheJSTLcoretagc:importtoincludethecontentsofthe/WEB-INF/javascript/validate.jsfile.SeeExample12-6forthecontentsofvalidate.js,whichisadefinitionforthefunctionvalidate.Thisfunctiondetermineswhethertheuserhasleftanyformfieldsblank.
TherestoftheJSPisstraightforward:theonSubmiteventhandlercallsthevalidatefunctionandpassesintheformobject(representedbytheJavaScriptkeywordthis)asaparameter.Byreturningfalse,thevalidatefunctioncancelstheformsubmitifitfindsanyblankfields.
Example12-8.AJSPusesJavaScripttovalidateHTMLforminput
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head>
<c:importurl="/WEB-INF/javascript/validate.js"/>
<title>HelpPage</title></head><body>
<h2>Pleasesubmityourinformation</h2>
<formaction="/home/displayHeaders.jsp"onSubmit="returnvalidate(this)">
<tableborder="0"><tr><tdvalign="top">
Yourname:</td><tdvalign="top">
<inputtype="text"name="username"size="20">
</td></tr><tr><tdvalign="top">
Youremail:</td><tdvalign="top">
<inputtype="text"name="email"size="20">
</td></tr>
<tr><tdvalign="top">
<inputtype="submit"value="SubmitInfo"></td></tr>
</table></form>
</body></html>
Figure12-4showsthewebpagecontainingtheform.Figure12-5depictsthealertwindowthatwouldbedisplayediftheuserleavesoneormoretextfieldsblankwhensubmittingtheform.
SeeAlso
TheNetscapeDevEdgesiteathttp://devedge.netscape.com/;Recipe12.2andRecipe12.4onusingJavaScriptwithJSPstoimportJavaScriptfunctiondefinitionsandcreatenewbrowserwindows;Recipe12.3on
creatingnewbrowserwindowswithservletsandJavaScript;Recipe12.5onvalidatingformvalueswithaservletandJavaScript;Recipe18.3onusingafilterwithHTTPrequests.
Chapter13.SendingNon-HTMLContentIntroduction
Recipe13.1.SendingaPDFFile
Recipe13.2.SendingaWordProcessingFile
Recipe13.3.SendinganXMLfile
Recipe13.4.SendinganAudioFile
Recipe13.5.ViewingInternalResourcesinaServlet
Introduction
Mostwebsitesofferasmorgasbordofmediatypestotheirusers.TypicalwebcontentthesedaysincludesPortableDocumentFormat(PDF)files,word-processingdocuments,audiofiles,movies,andExtensibleMarkupLanguage(XML).Insomecases,thesealternativefiletypesarestoredindatabasesasbinarydata,orstreamsofunencodedbytes.Webdeveloperscannotalwaysprovidetheiruserswithstraightforwardhyperlinkstothesefilesfordownloading.TheuserchoosesalinkorentersaURLinthebrowser'slocationfield,andaservletorsomeotherwebcomponentdownloadsthebinarydatatotheclient.Theclientinmostcasessavesthedataasafile,foruselaterindocumentviewersandotherapplications.
Thefollowingrecipesdescribehowtoinitiatethisdownloadmethod.Inatypicalscenario,theservletsetsupadownloadwherebythebrowserpromptstheuserwitha"SaveAs"dialogallowinghimtosavethefilesonhisownfilesystem.Thesestrategies,however,donotguarantee100-percentconsistentbehavioramongwebbrowsers.Somebrowsersallowtheusertopreciselyconfigurehowhewantstohandlehandlecertainfiletypes(suchasaPDFdocument).Forexample,Opera5givestheuserallkindsofoptionsfordealingwithdownloads,suchasopeningupanexternalhelperapplication,displayingafileusingaplug-in,orimmediatelydownloadingafiletoaspecifiedfolderwithoutfirstopeningupa"SaveAs"window.
Testhowyourwebapplicationworksinvariousbrowsers,inresponsetodifferentbrowserconfigurations,aswellasondifferentplatforms,sothatyouareawareofthedifferentbrowserresponseselicitedbytheservlet.
ThealternativetothesestrategiesissimplyprovidingalinktoaPDFfileforinstanceifthedataexistsasafile.Thismethod,however,also
placesagreatdealoftheresponsibilityontheclientbrowser,andtheuserwhoconfiguresthebrowser,formanagingthemediatype.Whileadvancedusersmaylikethisapproach,itisrarelysufficientforless-experiencedusers.
Recipe13.1SendingaPDFFile
Problem
YouwanttosendbinarydatarepresentingaPDFfiletoauser.
Solution
Useaservletandajava.io.BufferedInputStreamtoreadthebytesfromthefile.Sendthefilecontenttotheuserwithajavax.servlet.ServletOutputStreamretrievedfromthejavax.servlet.http.HttpServletResponseobject.
Discussion
PDFfilesareubiquitousontheWeb,asmostusersareequippedwiththeAdobeReaderapplicationthatreadsthem.Example13-1takesafilenamefromaquerystringthatispartoftherequesttotheservlet,andrespondswithbinarydatathatrepresentsthePDFfile.TheservletidentifiesthefilethatitsendstotheclientastheMIMEtypeapplication/pdfbyusingtheContent-Typeresponseheader.
MultipurposeInternetMailExtensions(MIME)designatethemediatypesofvariousdatathataresentasemailoraspartofHTTPresponsesontheWeb.AMIMEtypehasatop-leveltypeandasub-typeseparatedbyaforward-slashcharacter,asintext/html,application/pdf,oraudio/mpeg.TheContent-Typeresponseheaderisthemethodtheserverresponseusestoconveytheintendedtypeandformatofthedatathattheserversendstoanetworkclientsuchasawebbrowser.SeethefollowingRequestForComments(RFC)technicaldocumentsonMIMEformoreinformation:ftp://ftp.rfc-editor.org/in-notes/rfc2045.txtandftp://ftp.rfc-editor.org/in-notes/rfc2046.txt.
Table13-1showsseveralMIMEtypesthatwebdevelopersmayencounter.
Table13-1.SomecommonMIMEtypes
File MIMEtype Extension
XML text/xml .xml
HTML text/html .html
Plaintextfile text/plain .txt
PDF application/pdf .pdf
GraphicsInterchangeFormat(GIF)image image/gif .gif
JPEGimage image/jpeg .jpeg
PNGimage image/x-png .png
MP3musicfile audio/mpeg .mp3
ShockwaveFlashanimation application/futuresplashorapplication/x-shockwave-flash .swf
MicrosoftWorddocument application/msword .doc
Excelworksheet application/vnd.ms-excel .xls
PowerPointdocument application/vnd.ms-powerpoint .ppt
Therequesttotheservletlookslikethis:
http://localhost:8080/home/sendpdf?file=chapter5
Example13-1checkstoseeiftherequestparameterfileisvalidandthenaddsthefileextension.pdftothefilenameifitdoesnotalreadyhavethatsuffix.ThisisthefilenametheHTTPresponserecommendstothebrowser(itwillappearasthedefaultfilenameinanydisplayed"SaveAs"windows).
JasonHunterinJavaEnterpriseBestPractices(O'Reilly)pointsoutthatitisoftenusefultoincludetheintendedfilename(forthe"SaveAs"dialogboxthebrowserproduces)directlyintheURLasextrapathinfo.Thebrowserdetectsthatnameastherequestedresourceandmayspecifythenameinthe"SaveAs"dialogwindow.AnexampleURLinthiscaselookslike:
http://localhost:8080/home/chapter5.pdf?file=ch5
Example13-1.SendingaPDFfileasbinarydata
packagecom.jspservletcookbook;
importjava.io.FileInputStream;
importjava.io.BufferedInputStream;
importjava.io.File;
importjava.io.IOException;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSendPdfextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
IOException{
//getthefilenamefromthe"file"parameter
StringfileName=(String)request.getParameter("file");
if(fileName==null||fileName.equals(""))
thrownewServletException(
"Invalidornon-existentfileparameterinSendPdfservlet.");
//addthe.pdfsuffixifitdoesn'talreadyexist
if(fileName.indexOf(".pdf")==-1)
fileName=fileName+".pdf";
//wherearePDFskept?
StringpdfDir=getServletContext().getInitParameter("pdf-dir");
if(pdfDir==null||pdfDir.equals(""))
thrownewServletException(
"Invalidornon-existent'pdfDir'context-param.");
ServletOutputStreamstream=null;
BufferedInputStreambuf=null;
try{
stream=response.getOutputStream();
Filepdf=newFile(pdfDir+"/"+fileName);
//setresponseheaders
response.setContentType("application/pdf");
response.addHeader(
"Content-Disposition","attachment;filename="+fileName);
response.setContentLength((int)pdf.length());
FileInputStreaminput=newFileInputStream(pdf);
buf=newBufferedInputStream(input);
intreadBytes=0;
//readfromthefile;writetotheServletOutputStream
while((readBytes=buf.read())!=-1)
stream.write(readBytes);
}catch(IOExceptionioe){
thrownewServletException(ioe.getMessage());
}finally{
//closetheinput/outputstreams
if(stream!=null)
stream.close();
if(buf!=null)
buf.close();
}
}//enddoGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,IOException{
doGet(request,response);
}
}
Example13-1getsthedirectorywherethePDFfilesarestoredfromacontext-paramelementinthedeploymentdescriptor:
<context-param>
<param-name>pdf-dir</param-name>
<param-value>h:/book/distribute</param-value>
</context-param>
Rememberthatthecontext-paramelementsappearbeforethefilter,filter-mapping,listener,andservletelementsintheweb.xmlversionforservletAPI2.3.
ThecodethengetstheServletOutputStreamfromthe
HttpServletResponseobject.ThebinarydatarepresentingthePDFiswrittentothisstream:
stream=response.getOutputStream();
Theservletdoesnotuseajava.io.PrintWriterasinresponse.getWriter(),becauseaPrintWriterisdesignedforreturningcharacterdata,suchasHTML,thatthebrowserdisplaysonthecomputerscreen.Example13-1addstheresponseheadersthathelppreventthebrowsersfromtryingtodisplaythebytesascontentinthebrowserwindow:
response.setContentType("application/pdf");
response.addHeader(
"Content-Disposition","attachment;filename="+fileName);
response.setContentLength((int)pdf.length());
TheContent-Dispositionheaderfieldsignalstheclienttotreatthereceivedcontentasanattachment,notascharacterstobedisplayedinthebrowser.Thisoptionalresponseheaderalsoprovidesarecommendedfilename,whichthebrowsermayincludeasthedefaultfilenameinany"SaveAs"windows.
SeeRFC2183atftp://ftp.rfc-editor.org/in-notes/rfc2183.txtforbackgroundinformationontheContent-Dispositionheader.
TheclientbrowsercanusetheContent-Lengthheadervalue(providedwithresponse.setContentLength())toindicatetotheuserthedownloadprogresswithawidgetthatshowsahorizontalbarsteadilyfillingwithcolor.Theservletalsousesajava.io.BufferedInputStreamtobuffertheinputfromthefileinabyte[]array,whichspeedsupthetransferofdatafromtheservertotheclient.
SeeRecipe13.5foranexampleofusingajava.net.URLConnection(asopposedtoaFileInputStream)togetaninputstreamassociatedwithawebresource.AURLConnectionisusefulwhenyouwanttoobtainbinarydatafromaPDFfilethatisavailableonlyasawebaddressbeginningwith"http://".
ThecodeclosestheServletOutputStreamandtheBufferedInputStreaminafinallyblocktoreleaseanysystemresourcesusedbytheseobjects.Thecodewithinthefinallyblockexecutesregardlessofwhetherthecodethrowsanexception.
InternetExplorer5.5usuallyraisesanexceptionthatisdisplayedintheTomcatlogfilewhenarequestismadetothisrecipe'sservlet.Theloggedexceptiondoesnotdisrupttheapplication,nordoesitappearwhentheservletisrequestedbyOpera5,orbyInternetExplorer5.2andtheSafariMacintoshbrowsers.Theexceptionmessageincludesthetext"Connectionresetbypeer:socketwriteerror."Thismessagehasraisedspeculationonvariousservlet-relatedmailingliststhattheIEclientbrowseronWindowshascausedtheexceptionbyseveringtheconnectionwithTomcatafterthedatatransfer.Nobodyhasyetdevisedadefinitivesolutiontothisapparentlyharmlessexception,beyondsuggestingthattheservletcontainer'sloggingmechanismbeconfiguredtoignoreexceptionsofthistype.
SeeAlso
Recipe13.2-Recipe13.4onsendingWord,XML,andMP3filesasbinarydata;Recipe13.5ongettinganinputstreamrepresentingawebresourcesuchasweb.xml;RFCtechnicaldocumentsonMIME:ftp://ftp.rfc-editor.org/in-notes/rfc2045.txtandftp://ftp.rfc-editor.org/in-notes/rfc2046.txt.;RFC2183atftp://ftp.rfc-editor.org/in-notes/rfc2183.txtforbackgroundinformationontheContent-Dispositionheader;theMediaTypessectionoftheHTTPPocketReferencebyClintonLong(O'Reilly).
Recipe13.2SendingaWordProcessingFile
Problem
YouwanttosendaMicrosoftWordfileasbinarydata.
Solution
UsethesameservletsetupasdescribedinRecipe13.1,butincludeadifferentfileextensionandaContent-Typeofapplication/msword.
Discussion
YoumighthavesomeMicrosoftWorddocumentsthatyouwanttodistributeasbinarydatafromaservlet.Example13-2usesthesamebasicstructureasExample13-1,withafewchangestoadapttheservletforsendingMicrosoftWorddocuments.Theseincludeaccessingadifferentcontext-paramelement(youcouldkeepallfilesfordownloadinthesamedirectory,however),andusingadifferentMIMEtypeastheparameterforthesetContentType()method,asinresponse.setContentType("application/msword").
Example13-2.SendingaWordfileasbinarydata
packagecom.jspservletcookbook;
importjava.io.FileInputStream;
importjava.io.BufferedInputStream;
importjava.io.File;
importjava.io.IOException;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSendWordextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
IOException{
//getthefilenamefromthe"file"parameter
StringfileName=(String)request.getParameter("file");
if(fileName==null||fileName.equals(""))
thrownewServletException(
"Invalidornon-existentfileparameterinSendWord.");
//addthe.docsuffixifitdoesn'talreadyexist
if(fileName.indexOf(".doc")==-1)
fileName=fileName+".doc";
//whereareWordfileskept?
StringwordDir=getServletContext().getInitParameter("word-dir");
if(wordDir==null||wordDir.equals(""))
thrownewServletException(
"Invalidornon-existentwordDircontext-param.");
ServletOutputStreamstream=null;
BufferedInputStreambuf=null;
try{
stream=response.getOutputStream();
Filedoc=newFile(wordDir+"/"+fileName);
//setresponseheaders
response.setContentType("application/msword");
response.addHeader(
"Content-Disposition","attachment;filename="+fileName);
response.setContentLength((int)doc.length());
FileInputStreaminput=newFileInputStream(doc);
buf=newBufferedInputStream(input);
intreadBytes=0;
//readfromthefile;writetotheServletOutputStream
while((readBytes=buf.read())!=-1)
stream.write(readBytes);
}catch(IOExceptionioe){
thrownewServletException(ioe.getMessage());
}finally{
//closetheinput/outputstreams
if(stream!=null)
stream.close();
if(buf!=null)
buf.close();
}
}//enddoGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
IOException{
doGet(request,response);
}
}
TheServletOutputStream(theinformationsentastheservlet
response)andtheBufferedInputStream(fromwhichtheservletgetsthefiletosend)arebothclosedinthefinallyblocktomakesureanysystemresourcestheyusearereleased.SeetheendofthediscussioninRecipe13.1forafurtherdescriptionofthiscode,includingthewarningattheendofthatrecipeabouttheInternetExplorer-relatedexception.
SeeAlso
Recipe13.1onsendingaPDFfile;Recipe13.3andRecipe13.4onsendingXMLandMP3filesasbinarydata;Recipe13.5ongettinganinputstreamrepresentingawebresourcesuchasweb.xml;RFCtechnicaldocumentsonMIME:ftp://ftp.rfc-editor.org/in-notes/rfc2045.txtandftp://ftp.rfc-editor.org/in-notes/rfc2046.txt;RFC2183atftp://ftp.rfc-editor.org/in-notes/rfc2183.txtforbackgroundinformationontheContent-Dispositionheader;theMediaTypessectionoftheHTTPPocketReferencebyClintonWong(O'Reilly);Chapter1introducingthedevelopmentofaservlet.
Recipe13.3SendinganXMLfile
Problem
YouwanttosendanXMLfileasbinarydatafromaservlet.
Solution
Usethejavax.servlet.ServletOutputStreamobtainedfromthejavax.servlet.http.HttpServletResponseobjecttosendtheXMLfileasbinarydatatotheclient.
Discussion
ThisrecipedescribeshowtosendanXMLfileasbinarydatafromaServletOutputStream,sothattheusercanhandlethefileasdownloadedXML.Example13-3obtainsthebytesthatrepresenttheXMLasaBufferedInputStreamwrappedaroundaFileInputStream.ThecodeisverysimilartoExample13-1inRecipe13.1,exceptthatitusesaMIMEtypeoftext/XML.
InapopularformofconvertingXMLintoareadableformat,youcouldconverttheXMLcontenttoHTMLoranotherformusingExtensibleStylesheetLanguageTransformations(XSLT).IftheintentistouseXSLTforgeneratingthecontentinabrowser,leaveouttheContent-Dispositionresponseheader,becausethisheaderisdesignedtohandletheXMLasadownloadedfilethatwillbesavedintheuser'sfilesystem.SeeChapter23onusingthex:transformJSTLtag.
Example13-3.SendinganXMLfilewithaservlet
packagecom.jspservletcookbook;
importjava.io.FileInputStream;
importjava.io.BufferedInputStream;
importjava.io.File;
importjava.io.IOException;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSendXmlextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
IOException{
//getthefilenamefromthe"file"parameter
StringfileName=(String)request.getParameter("file");
if(fileName==null||fileName.equals(""))
thrownewServletException(
"Invalidornon-existentfileparameterinSendXmlservlet.");
//addthe.xmlsuffixifitdoesn'talreadyexist
if(fileName.indexOf(".xml")==-1)
fileName=fileName+".xml";
//whereareXMLfileskept?
StringxmlDir=getServletContext().getInitParameter("xml-dir");
if(xmlDir==null||xmlDir.equals(""))
thrownewServletException(
"Invalidornon-existentxmlDircontext-param.");
ServletOutputStreamstream=null;
BufferedInputStreambuf=null;
try{
stream=response.getOutputStream();
Filexml=newFile(xmlDir+"/"+fileName);
//setresponseheaders
response.setContentType("text/xml");
response.addHeader(
"Content-Disposition","attachment;filename="+fileName);
response.setContentLength((int)xml.length());
FileInputStreaminput=newFileInputStream(xml);
buf=newBufferedInputStream(input);
intreadBytes=0;
//readfromthefile;writetotheServletOutputStream
while((readBytes=buf.read())!=-1)
stream.write(readBytes);
}catch(IOExceptionioe){
thrownewServletException(ioe.getMessage());
}finally{
//closetheinput/outputstreams
if(stream!=null)
stream.close();
if(buf!=null)
buf.close();
}//finally
}//enddoGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,IOException{
doGet(request,response);
}
}
Forthecontext-paramtoworkcorrectlyinthiscode,youhavetoincludeinweb.xmlanelementthatlookslike:
<context-param>
<param-name>xml-dir</param-name>
<param-value>h:/home/xml</param-value>
</context-param>
SeeChapter1ifyouneedanintroductionorrefresherforthedeploymentdescriptorweb.xml.
ThediscussioninRecipe13.1describesthebasicmechanicsofthiscode,soIdon'trepeatthatinformationhere.SeethenoteattheendofRecipe13.1abouttheInternetExplorer-relatedexceptionthatyoumayexperiencewithservletsofthistype.
SeeAlso
Recipe13.1onsendingaPDFfile;Recipe13.2onsendingaMicrosoftWordfileasbinarydata;Recipe13.4onsendingMP3filesasbinarydata;Recipe13.5ongettinganinputstreamrepresentingawebresourcesuchasweb.xml;theRFCtechnicaldocumentsonMIME:
ftp://ftp.rfc-editor.org/in-notes/rfc2045.txtandftp://ftp.rfc-editor.org/in-notes/rfc2046.txt;RFC2183atftp://ftp.rfc-editor.org/in-notes/rfc2183.txtforbackgroundinformationontheContent-Dispositionheader;theMediaTypessectionoftheHTTPPocketReferencebyClintonWong(O'Reilly);Chapter1introducingthedevelopmentofaservlet;atutorialonjava.sun.comonXSLT:http://java.sun.com/webservices/docs/1.1/tutorial/doc/JAXPXSLT.html#wp68287
Recipe13.4SendinganAudioFile
Problem
YouwanttosendanaudiofilesuchasanMPEGlayer3(MP3)mediatype.
Solution
Useajava.io.BufferedInputStreamtofetchtheaudiodata,andthejavax.servlet.ServletOutputStreamfromthejavax.servlet.http.HttpServletResponseobjecttosendthedatatotheclient.
Discussion
ThecodeinExample13-4usesthesameapproachasthepriorrecipes,exceptfortheMIMEtype,whichisspecifiedasaudio/mpeg.
WebbrowsersassociateanumberofotherMIMEtypesforMP3files,includingaudio/x-mpeg,audio/mp3,andaudio/x-mp3.
TheuserrequestsafilenameintheURL,asin:
http://localhost:8080/home/sendmp3?file=song_name
Thedeploymentdescriptor(web.xml)mapstheservletpath/sendmp3to
theservletclassofExample13-4:com.jspservletcookbook.SendMp3.Iftherequestedfiledoesnotalreadyhavethe.mp3suffix,thenthecodeaddsthatfileextension.Acontext-paramelementinthedeploymentdescriptorspecifiesthedirectorywheretheaudiofilesarekept:
<context-param>
<param-name>mp3-dir</param-name>
<param-value>h:/home/mp3s</param-value>
</context-param>
Example13-4usesthisdirectoryname,plusthefilename,astheconstructorparametertocreateanewjava.io.Fileobject,whichisthesourceforajava.io.FileInputStream.ABufferedInputStreambuffersthebytesfromthesongfile,whichtheServletOutputStreamresponsereads.
Example13-4.SendinganMP3file
packagecom.jspservletcookbook;
importjava.io.FileInputStream;
importjava.io.BufferedInputStream;
importjava.io.File;
importjava.io.IOException;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSendMp3extendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,IOException{
//getthefilenamefromthe"file"parameter
StringfileName=(String)request.getParameter("file");
if(fileName==null||fileName.equals(""))
thrownewServletException(
"Invalidornon-existentfileparameterinSendMp3servlet.");
//addthe.mp3suffixifitdoesn'talreadyexist
if(fileName.indexOf(".mp3")==-1)
fileName=fileName+".mp3";
//whereareMP3fileskept?
Stringmp3Dir=getServletContext().getInitParameter("mp3-dir");
if(mp3Dir==null||mp3Dir.equals(""))
thrownewServletException(
"Invalidornon-existentmp3-Dircontext-param.");
ServletOutputStreamstream=null;
BufferedInputStreambuf=null;
try{
stream=response.getOutputStream();
Filemp3=newFile(mp3Dir+"/"+fileName);
//setresponseheaders
response.setContentType("audio/mpeg");
response.addHeader(
"Content-Disposition","attachment;filename="+fileName);
response.setContentLength((int)mp3.length());
FileInputStreaminput=newFileInputStream(mp3);
buf=newBufferedInputStream(input);
intreadBytes=0;
//readfromthefile;writetotheServletOutputStream
while((readBytes=buf.read())!=-1)
stream.write(readBytes);
}catch(IOExceptionioe){
thrownewServletException(ioe.getMessage());
}finally{
//closetheinput/outputstreams
if(stream!=null)
stream.close();
if(buf!=null)
buf.close();
}
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,IOException{
doGet(request,response);
}
}
ReviewRecipe13.1forafurtherexplanationofthiscode,includingthewarningattheendofthe"Discussion"sectionaboutloggedexceptionsthatmayoccurwithInternetExplorer.
SeeAlso
Recipe13.1onMIMEtypesandsendingaPDFfileasbinarydata;Recipe13.2andRecipe13.3onsendingWordandXMLfiles,respectively,asbinarydata;Recipe13.5onreceivinganinputstreamrepresentingawebresourcesuchasweb.xml;theRFCtechnicaldocumentsonMIME:ftp://ftp.rfc-editor.org/in-notes/rfc2045.txtand
ftp://ftp.rfc-editor.org/in-notes/rfc2046.txt;RFC2183atftp://ftp.rfc-editor.org/in-notes/rfc2183.txtforbackgroundinformationontheContent-Dispositionheader;theMediaTypessectionoftheHTTPPocketReferencebyClintonWong(O'Reilly);Chapter1introducingthedevelopmentofaservlet.
Recipe13.5ViewingInternalResourcesinaServlet
Problem
Youwanttouseaservlettofetchinternalresourcesfromawebapplicationforviewingbyauthenticatedusers.
Solution
Usethejavax.servlet.ServletContext.getResource(Stringpath)methodtogeneratetheinputstreamfromthewebresource.
Discussion
Aservletcouldbeusedwhileawebapplicationisindevelopmenttoprovideaviewofthedeploymentdescriptor.Webdevelopersoftenhavetodouble-checkweb.xmlforthevaluesofcontext-paramelements,aservlet'sregisteredname,andotherinformation.Wouldn'titbenicetojustrequestaservletinthebrowsertoviewweb.xml?
Example13-5opensupweb.xmlusingtheServletContext.getResource()method,whichreturnsajava.net.URLobjectrepresentingthedeploymentdescriptoratthepathWEB-INF/web.xml.
ThecodeopensaconnectiontotheXMLfilebycallingtheURLobject'sopenConnection()method,whichreturnsajava.net.URLConnectionobject.ThenthecodebufferstheinputstreamtotheresourcebywrappingitinaBufferedInputStream:
buf=newBufferedInputStream(urlConn.getInputStream());
TheurlConnvariablereferstoaURLConnection.
IfthebrowserisnotsavvyaboutdisplayingXMLfilesinareadablefashion(Netscape7.1andInternetExplorercandisplaythesefilesproperly),youcanuseXSLTtoconverttheXMLintoHTMLbeforeitissenttothebrowser.
Example13-5.Displayingthedeploymentdescriptorviaaservlet
packagecom.jspservletcookbook;
importjava.io.BufferedInputStream;
importjava.io.PrintWriter;
importjava.io.IOException;
importjava.net.URL;
importjava.net.URLConnection;
importjava.net.MalformedURLException;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassResourceServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
IOException{
//getweb.xmlfordisplaybyaservlet
Stringfile="/WEB-INF/web.xml";
URLurl=null;
URLConnectionurlConn=null;
PrintWriterout=null;
BufferedInputStreambuf=null;
try{
out=response.getWriter();
//accessawebresourcewithinthesamewebapplication
//asaURLobject
url=getServletContext().getResource(file);
//setresponseheader
response.setContentType("text/xml");
urlConn=url.openConnection();
//establishconnectionwithURLrepresentingweb.xml
urlConn.connect();
buf=newBufferedInputStream(urlConn.getInputStream());
intreadBytes=0;
//readfromthefile;writetothePrintWriter
while((readBytes=buf.read())!=-1)
out.write(readBytes);
}catch(MalformedURLExceptionmue){
thrownewServletException(mue.getMessage());
}catch(IOExceptionioe){
thrownewServletException(ioe.getMessage());
}finally{
//closetheinput/outputstreams
if(out!=null)
out.close();
if(buf!=null)
buf.close();
}
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,IOException{
doGet(request,response);
}
}
Thisservletisdesignedfordevelopers;ifjustanyonehasachancetostudythedeploymentdescriptor,itwillcompromisethewebapplication'ssecurity.Therefore,youshouldremovetheservletfromproductionversionsofthewebapplication,oruseauthenticationtoallowonlyauthorizeduserstoviewtheservlet'soutput(seeChapter15fordetails).
ThecodeusesaPrintWritertowritethebytesreceivedfromtheinputstream,becausetheservletintendstodisplaytheresponseascharacters(insteadofofferingtheresponsetotheclientasadownloadedresource).TheServletContext.getResource(Stringpath)methodtakesapaththatbeingswiththe/character.Thepathisinterpretedasbeginningatthecontextroot,ortop-leveldirectory,ofthewebapplication.Therefore,theservletobtainsweb.xmlwiththefollowing
code:
Stringfile="/WEB-INF/web.xml";
...
url=getServletContext().getResource(file);
TheServletContext.getResouce()methodreturnsnullifitisunabletoreturnavalidresourcerepresentingthepathparameter.
SeeAlso
Recipe13.1-Recipe13.4onsendingPDF,Word,XML,andaudiofiles,respectively,asbinarydata;theRFCtechnicaldocumentsonMIME:ftp://ftp.rfc-editor.org/in-notes/rfc2045.txtandftp://ftp.rfc-editor.org/in-notes/rfc2046.txt;RFC2183atftp://ftp.rfc-editor.org/in-notes/rfc2183.txtforbackgroundinformationontheContent-Dispositionheader;theMediaTypessectionoftheHTTPPocketReferencebyClintonWong(O'Reilly);Chapter1introducingthedevelopmentofaservlet.
Chapter14.LoggingMessagesfromServletsandJSPs
Introduction
Recipe14.1.LoggingWithoutLog4j
Recipe14.2.SettingUpLog4j
Recipe14.3.UsingaLoggerWithoutaConfigurationFile
Recipe14.4.AddinganAppendertotheRootLogger
Recipe14.5.UsingaPatternwithaLogger'sAppender
Recipe14.6.Usinglog4jinaJSP
Recipe14.7.LoggingMessagesUsingaServletContextEventListener
Recipe14.8.LoggingMessagesUsingaSessionEventListener
Introduction
Logginginvolvessendingmessagesfromyourapplicationanddisplayingthisinformationinavarietyofwaysforwebdevelopersandadministrators.Themessagescanbedeliveredtoaconsole,ortheycanbestoredpersistentlyinfilesordatabases.Loggingmaybeusedonlyforsendingdebug-relatedinformationwhileawebapplicationisbeingdeveloped,orthesemessagesmayprovideinformationfromanapplicationinproduction,includingdataaboutwarningsandfatalerrors.
Thischapterdescribesaverypowerfulopensourceloggingtoolcalledlog4j.ThisisaJavaARchive(JAR)file(log4j-1.2.8.jar)thatyoucanaddtoyourwebapplicationbyplacingitinyourWEB-INF/libdirectory.Thismakesitavailableforuseinanyservletsorbeansthatyouwanttosendloggingmessagesfrom.Thissectionprovidesonlyabriefintroductiontolog4j,becauseitspowerdoesentailsomecomplexity.
log4jinvolvesthreemainconcepts:loggers,appenders,andlayouts.log4jusesanexternalconfigurationfile,similartoadeploymentdescriptor,toconfigurethesethreeloggingelements.Theupcomingrecipesprovidesomeexamplesoftheseconfigurationfiles,whicharemostlysimpletextfilesinvolvingalistofname/valuepairs.Thepowerofusingexternalfilesisthatyoucanchangethepropertiesinthesetextfilestoalteralogger(forinstance,modifytheformatofitsmessages)insteadofrecompilingtheservletcode.
Forthechangestotakeeffect,youmayrequireareloadoftheservletorothercomponentthatinitializestheloggingsystemfortheapplication.
Loggers
Aloggeristheentitythataservletusestologmessages.Touseone,importthelog4jclassesintotheservlet,createaninstanceofalogger(specificallyanorg.apache.log4j.Logger),thencallthelogger'smethods.Themethodsarenamedafterthelogginglevelofthemessage.Forexample,tologaninformationalmessage(anINFOlevel)youwouldcall:
logger.info("HttpServletinitmethodcalled.");
log4jhasfivedifferentlevelsoflogcategories:DEBUG,INFO,WARN,ERROR,andFATAL.ThelogcategoriesareorganizedinascendingorderbeginningwithDEBUGaloggerconfiguredforINFO-levellogginglogsonlyINFO,WARN,ERROR,andFATALmessages(butnotDEBUG-levelmessages,becauseinthishierarchyDEBUGisbeneathINFOandtheotherlevels).Hereisabriefdescriptionofthepurposeofeachlevel:
DEBUGinvolvesloggingmessageswhileinitiallydevelopinganddebugginganapplication.
INFOhelpsyoumonitortheprogressofanapplication.
WARNdesignatespotentiallyharmfulsituations.
ERRORrepresentsanerrorthattheapplicationcanlikelyrecoverfrom.
FATALsuggestserrorsthatwillcauseanapplicationtoabort.
Everyloggerisconfiguredwithalevel(suchasDEBUG)inthelog4jpropertiesorconfigurationfile(seeRecipe14.4).log4jalsoassociatesthemessagesthatyoulogwithaspecifiedlevel,whichmakesiteasytousebecausethemethodnamesarethesameasthelevelnames.Theloggerdoesnotsendthesemessagesunlessthelogger'slevelisequaltoorgreaterthanthelevelrepresentedbythemethodcall(asinlogger.debug(Objectmessage)).
Forexample,let'ssayyouconfiguretheloggerwithalevelofDEBUG,thendevelopaservletwithanumberoflogger.debug(Objectmessage)calls.
Later,youcanchangetheconfigurationfileandgivetheloggeranINFOlevel.Changingtheconfigurationinthismanner"turnsoff"DEBUG-levellogginginthatservlet,sothattheseloggingmessagesnolongershowupinthelogfiles,database,orotherloggingrepository.ThisisbecauseDEBUGisnotequaltoorgreaterthanINFOinthehierarchyofloggingcategories.
Similarly,youcanturnbackonDEBUG-levellogginginthepriorexamplebysimplyswitchingthelogger'sconfigurationbackfromINFOtoDEBUG.Asaresult,thedebug-levelmessageswillnolongerbefilteredout.
ProgrammerswritingsoftwarewithseveralDEBUG-levelmethodcallscaneasilyswitchintoWARN-orERROR-leveldebuggingoncetheapplicationmovesintoitsnextstageofdevelopment,orgoesintoproduction.
Appenders
log4jisalsoverypowerfulintermsofthedifferentwaysyoucanlogmessages.Youcanuselog4jtologmessagestoaconsole,afile,arollingfile(whichautomaticallycreatesabackupfilewhenalogfilereachesaspecifiedsize),adatabase,anemailserver,andseveralothertypesoflogrepositories.log4jcallseachoftheseloggingmechanismsanappender.Recipe14.4introducestheconfigurationfileinwhichyoucandescribeappenders.
Layouts
Whatdoestheactualloggedmessagelooklike?Whatinformationdoesitinclude?log4jshinesinthisareatoo.Youcanspecifynumerousdifferentlayoutsforthemessagesusingthelog4jconfigurationfile.log4jletsyou
specifyverycomplex(orsimple)layoutsusingconversionpatterns,whicharesomewhatsimilartoregularexpressions.Toachievethemostbasiclayout,youcanspecifyanorg.apache.log4j.SimpleLayout.Withthisformat,thelogcontainsthelevelname,followedbyadash(-)andtheactualmessage:
INFO-HttpServletinitmethodcalled.
Usinganorg.apache.log4j.PatternLayoutismorepowerful,andRecipe14.5providessomeexamplesofdifferentlayoutsforloggingmessages.
Recipe14.1LoggingWithoutLog4j
Problem
Youwanttoputamessageintheserverlogs.
Solution
CalltheServletContext.log()methodinsidetheservlet.
Discussion
Ifyoujustwanttologamessageintheservletcontainer'slogfileanddonotneedthepoweroflog4j,usetheServletContext.log()method.Example14-1showsthetwoversionsofthelog()method.OnetakestheStringmessageasaparameter,andtheotherhastwoparameters:aStringmessageandaThrowable.TheservletlogwillcontainthestacktraceoftheThrowableifyouusethislog()form.
Example14-1.AservletusestheServletContext.log()method
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassContextLogextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
StringyourMessage=request.getParameter("mine");
//CallthetwoServletContext.logmethods
ServletContextcontext=getServletContext();
if(yourMessage==null||yourMessage.equals(""))
//logversionwithThrowableparameter
context.log("Nomessagereceived:",
newIllegalStateException("Missingparameter"));
else
context.log("Hereisthevisitor'smessage:"+yourMessage);
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
//loggingservletsprobablywanttodisplaymoreHTML
out.println(
"<html><head><title>ServletContextlogging</title></head><body>");
out.println("<h2>Messagessent</h2>");
out.println("</body></html>");
}//doGet
}
TheServletContextlogsitstextmessagestotheservletcontainer'slogfile.WithTomcattheselogsarefoundin<Tomcat-installation-directory>/logs.BelowistheoutputofExample14-1andthesecondformofServletContext.log(),whichprintsthemessageandtheThrowable'sstacktrace(onlythefirsttwolevelsofthemethodstackareshown).Youcanseethatthelogincludesthedateandtimeoftheloggingactivity,andthemessagetext:
2003-05-0814:42:43Nomessagereceived:
java.lang.IllegalStateException:Missingparameter
atcom.jspservletcookbook.ContextLog.doGet(UnknownSource)
atjavax.servlet.http.HttpServlet.service(HttpServlet.java:740)
...
Thesingle-parameterformofthelog()methodsimplydisplaysthedate,time,andtextofthemessage,asinthefirstlineofthepriorlogsample.Eachlog()methodcallplacesthemessageonanewlineintheserverlogfile.
SeeAlso
Recipe14.2-Recipe14.8onusinglog4jtodesignyourowncustomloggingmechanism;ChapterSRV.3oftheservletAPIontheservletcontext;linkstothelatestservletspecification:http://java.sun.com/products/servlet/index.html.
Recipe14.2SettingUpLog4j
Problem
Youwanttosetuplog4jforuseinyourwebapplication.
Solution
Downloadthelog4jdistributionfromtheApacheJakartaprojectandplacetheaccompanyinglog4j-1.2.8.jarfile(thenamewillbedifferentfordifferentlog4jversions)intheWEB-INF/libdirectoryofyourwebapplication.
Discussion
Thelog4jpackageisavailableforuseundertheApacheSoftwareLicense,whichisincludedwiththedistribution.Herearethestepsforsettinguplog4jforyourwebapplication:
1. Gotothelog4jwebsiteanddownloadthedistributioninZIP(Windows)orgzipped(Unix-basedsystems)format:http://jakarta.apache.org/log4j/docs/download.html.Thedownloadedfilewillbenamedsomethinglikejakarta-log4j-1.2.8.ziporjakarta-log4j-1.2.8.tar.gz.
Unpackthedistribution,whichcreatesadirectoryjakarta-log4j-1.2.8(forVersion1.2.8oflog4j).Insidethedistdirectoryofthistop-leveldirectoryisthelog4j-1.2.8.jarfile.CopythisJARfileintotheWEB-INF/libdirectoryofyourwebapplication(s).
Createalog4jpropertiesfileandplaceitinthewebapplication's
WEB-INF/classesdirectory.Thisistypicallyatextfilewithname/valuepairsforconfiguringlog4jelementssuchasloggers,appenders,andlayouts.Recipe14.4includesanexampleofthisfile.
Intheservletsorbeanswhereyouwillusealogger,includetheproperimportstatements.Example14-2isaskeletalservletshowingtheclassesthatyoumighttypicallyuse.
Example14-2.Importinglog4j-relatedpackages
importorg.apache.log4j.Logger;
importorg.apache.log4j.PropertyConfigurator;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassLoggerSkelextendsHttpServlet{
privateLoggerlog;
publicvoidinit(){
//log4jwillfindthelog4j.propertiesfile
//inWEB-INF/classes
log=Logger.getLogger(LoggerSkel.class);
//Justanexampleofusingthelogger
log.debug("Instancecreatedof:"+getClass().getName());
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//dologginghereifnecessary
}//doGet
}
Aslongaslog4j-1.2.8.jarislocatedinWEB-INF/lib,yourservletcanusethenecessaryclassesfromtheorg.apache.log4j.*packages.
SeeAlso
Recipe14.3-Recipe14.8onusinglog4jtodesignyourowncustomloggingmechanism;thelog4jdownloadsite:http://jakarta.apache.org/log4j/docs/download.html;thelog4jprojectdocumentationpage:http://jakarta.apache.org/log4j/docs/documentation.html.
Recipe14.3UsingaLoggerWithoutaConfigurationFile
Problem
Youwanttousealoggerinaservletwithoutsettingupyourownconfigurationfile.
Solution
Createtheloggerintheservletandusetheorg.apache.log4j.BasicConfiguratorclasstoconfigurethelogger.
Discussion
log4jallowstheconfigurationofaloggerwithoutaprovidedconfigurationorpropertiesfile.Example14-3isaservletthatinstantiatesaloggerinitsinit()method,whichtheservletcontainercallswhentheservletinstanceiscreated.ThestaticBasicConfigurator.configure()methodcreatesaConsoleAppender;inotherwords,theloggerwilllogitsmessagestotheconsoleusingadefaultformat.
Example14-3.AservletusesBasicConfiguratortoconfigurealogger
packagecom.jspservletcookbook;
importorg.apache.log4j.Logger;
importorg.apache.log4j.BasicConfigurator;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassLoggerNconfigextendsHttpServlet{
privateLoggerlog=null;
publicvoidinit(){
//usetherootlogger
log=Logger.getRootLogger();
//thisloggerwilllogtotheconsolewithadefaultmessageformat
BasicConfigurator.configure();
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//displayaDEBUGlevelmessage
log.debug("SendingaDEBUGmessage");
//displayanINFOlevelmessage
log.info("SendinganINFOmessage");
//betterdisplaysomeHTML
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Servletlogging</title></head><body>");
out.println("<h2>HellofromaLoggerwithnoConfigfile</h2>");
//Thislogger'sparentistherootlogger
out.println(
"Yourloggernameis:"+log.getName()+"<br>");
out.println(
"Yourloggerparentis:"+log.getParent().getName()+"<br>");
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
doGet(request,response);
}
}
Example14-4showsanexamplemessagefromtheservlet.Themessageisbasedonadefaultformatthatincludesthethreadname(Thread-5),thelevelname(DEBUG),theloggername(com.jspservletcookbook.LoggerNconfig),andtheactualmessage("SendingaDEBUGmessage").Recipe14.5showshowtocreateaformatpatternforloggingmessages,sothatyoucancustomizethetypeofinformationthattheloggersends.
Example14-4.ExampleofaloggedmessageusingBasicConfigurator
4061660[Thread-5]DEBUGcom.jspservletcookbook.LoggerNconfig-SendingaDEBUGmessage
4061660[Thread-5]INFOcom.jspservletcookbook.LoggerNconfig-SendinganINFOmessage
HereisthepatternusedforthelayoutassociatedwithBasicConfigurator:
%-4r[%t]%-5p%c%x-%m%n
SeeRecipe14.5fordetailsontheorg.apache.log4j.PatternLayoutclass.
SeeAlso
Recipe14.2ondownloadingandsettinguplog4j;Recipe14.4-Recipe14.8onusinglog4jtodesignyourowncustomloggingmechanism;thelog4jdownloadsite:http://jakarta.apache.org/log4j/docs/download.html;thelog4jJavadocpage:http://jakarta.apache.org/log4j/docs/api/index.html;thelog4jprojectdocumentationpage:http://jakarta.apache.org/log4j/docs/documentation.html.
Recipe14.4AddinganAppendertotheRootLogger
Problem
Youwanttoconfigureanappenderorloggingdestinationfortherootlogger.
Solution
Createaconfigurationfilecalledlog4j.propertiesandplaceitintheWEB-INF/classesdirectoryofyourwebapplication.
Discussion
Nowourdiscussionmovesontothelog4jconfigurationfile,wheredeveloperscancustomizeloggers,appenders,andlayouts.Herearethestepsforusingthisrecipe'sexamples:
1. Createapropertiesfilenamedlog4j.properties(itscontentslooklikeExample14-5).
PlacethepropertiesfileintheWEB-INF/classesdirectoryofthewebapplication.
Importthisclassintoyourservlet:org.apache.log4j.Logger.
Intheservlet,getareferencetotherootloggerwiththestaticLogger.getRootLogger()method,andstartlogging.
Example14-5configurestherootlogger,akindof"superlogger"foryourapplication,withaDEBUGlevel.Therootloggerusesanappendernamedcons.Thisappenderisofatypeorg.apache.log4j.ConsoleAppender,meaningthatitsendsitslogmessagestotheconsole.
Example14-5.Thelog4j.propertiesfileforcreatingarootloggerappender
log4j.rootLogger=DEBUG,cons
log4j.appender.cons=org.apache.log4j.ConsoleAppender
log4j.appender.cons.layout=org.apache.log4j.SimpleLayout
Thethirdlineofthelog4j.propertiesfilestatesthattheloggerwilluseaSimpleLayout,whichlogsthelevelname(DEBUG),adash(-),andthemessageitself.Example14-6showstheservletthatisusingthelogger.log4jwillfindthelog4j.propertiesfileautomaticallyinWEB-INF/classesbecausetheservlethasnototherwiseconfiguredtheloggerwithacalltoBasicConfigurator.configure(),asshowninRecipe14.3.
Example14-6.Usingtherootloggerconfiguredwiththelog4j.propertiesfile
packagecom.jspservletcookbook;
importorg.apache.log4j.Logger;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassLoggerWconfigextendsHttpServlet{
privateLoggerlog=null;
publicvoidinit(){
//Therootloggerwillgetitsconfigurationfrom
//WEB-INF/classes/log4j.properties
log=Logger.getRootLogger();
log.info("LoggerWconfigstarted.");
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//displayaDEBUG-levelmessage
log.debug("SendingaDEBUGmessage");
//displayanINFO-levelmessage
log.info("SendinganINFOmessage");
//betterdisplaysomeHTML
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Servletlogging</title></head><body>");
out.println(
"<h2>HellofromaLoggerwithalog4j.propertiesfile</h2>");
out.println("Yourloggernameis:"+log.getName()+"<br>");
out.println("</body></html>");
}//enddoGet
}
Example14-6logsanINFOmessageintheservlet'sinit()method,thenlogstwomessagesintheservlet'sdoGet()servicemethod.Theloggerlogsallofthesemessagestotheconsolebecausethisishowthelog4j.propertiesfileconfigurestherootlogger'sappender.Thisiswhattheconsoleoutputlookslike:
INFO-LoggerWconfigstarted.
DEBUG-SendingaDEBUGmessage
INFO-SendinganINFOmessage
Figure14-1showstheservlet'soutputinawebbrowser.
Figure14-1.Theloggerdisplaysitsnameinaservlet
SeeAlso
Recipe14.2ondownloadingandsettinguplog4j;Recipe14.3onusingalog4jloggerwithoutapropertiesfile;Recipe14.5-Recipe14.8onusinglog4jtodesignyourowncustomloggingmechanism;thelog4jdownloadsite:http://jakarta.apache.org/log4j/docs/download.html;thelog4jJavadocpage:http://jakarta.apache.org/log4j/docs/api/index.html;thelog4jprojectdocumentationpage:http://jakarta.apache.org/log4j/docs/documentation.html.
Recipe14.5UsingaPatternwithaLogger'sAppender
Problem
Youwanttocreateyourownloggerforaservletandgivetheloggeranappender.
Solution
Includetheappenderconfigurationinthelog4j.propertiesfile.
Discussion
Thisrecipecreatesanewlogger,whichbringsustothediscussionoflog4j'sinheritancestructure.Therootloggeristhe"superlogger"thatalllogger'sinheritfrom,similartojava.lang.ObjectinJava'sobjectorientedprogrammingsetup.Example14-7createsanewloggernamedcom.jspservletcookbook,whichinheritstherootlogger'slevel(DEBUG)andconsoleappender(namedcons).Example14-7alsocreatesanappenderforthecom.jspservletcookbooklogger.Placethislog4j.propertiesfileintheWEB-INF/classesdirectory.
Example14-7.Theconfigurationforaloggernamedcom.jspservletcookbook
log4j.rootLogger=DEBUG,cons
log4j.logger.com.jspservletcookbook=,myAppender
#therootlogger'sappender
log4j.appender.cons=org.apache.log4j.ConsoleAppender
#thecom.jspservletcookbooklogger'sappender
log4j.appender.myAppender=org.apache.log4j.RollingFileAppender
log4j.appender.myAppender.File=h:/home/example.log
log4j.appender.myAppender.MaxBackupIndex=1
log4j.appender.myAppender.MaxFileSize=1MB
#therootlogger'slayout
log4j.appender.cons.layout=org.apache.log4j.SimpleLayout
#thecom.jspservletcookbooklogger'slayout
log4j.appender.myAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.myAppender.layout.ConversionPattern=%-5pLogger:%c{1}
Date:%d{ISO8601}-%m%n
YouprobablynoticedthesimilaritybetweenpackagenamesandthenameofthenewloggerinExample14-7:com.jspservletcookbook.log4jusesanamingschemebasedonJava's.Here'sthebasicrundownonthisscheme:
Allloggersinheritfromtherootlogger.
Allloggerswhosenamecontainsaprefixthatmatchesaconfiguredlogger'sname(suchascom.jspservletcookbook)alsoinheritfromthatconfiguredlogger.Therefore,aloggernamedcom.jspservletcookbook.LoggerWconfigderivesitscharacteristicsfromthecom.jspservletcookbooklogger.
InExample14-7,thecom.jspservletcookbookloggerspecifiesthatitwilluseanappendernamedmyAppender.ThemyAppender
appenderisarollingfileappender,whichisalogfilethatautomaticallycreatesabackupfilewhentheoriginallogreachesacertainsize.TheappenderisbasedontheJavaclassorg.apache.log4j.RollingFileAppender,whichisamongthesetofclassesthatlog4juses.
IfyoulookattheJavadocforthatclass,thenyouseethatithasabunchofmethodsthatlooklikegetXXX(),whereXXXisoneofthelogger'sproperties.Yousetthesepropertiesoftheappenderintheconfigurationfilebygivingeachpropertyavalue.TosetthemyAppenderappender'sFileproperty,thesyntaxis:
log4j.appender.myAppender.File=h:/home/example.log
Thisconfigurationelementspecifiesthefilelocationwheretheappenderwilllogitsmessages.WhenthisfilereachesitsMaxFileSizeof1MB,log4jrenamesthefileexample.log.1andcreatesanewexample.logtoreceivelogmessages.TheMaxBackupIndexmeansthatlog4jwillcreateonlyonebackupfile.
TheJavadocforRollingFileAppendercanbefoundat:http://jakarta.apache.org/log4j/docs/api/org/apache/log4j/RollingFileAppender.html.
Example14-7alsospecifiesalayoutforthecom.jspservletcookbooklogger,andaratherelaborateoneatthat:
log4j.appender.myAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.myAppender.layout.ConversionPattern=%-5pLogger:%c{1}Date:
%d{ISO8601}-%m%n
ThefirstlinespecifiesthatthemyAppenderlayoutwilluseanorg.apache.log4j.PatternLayout,whichisbasedonthe
conversionpatternoftheprintffunctioninC,accordingtothePatternLayoutJavadoc.Thispatternlanguagecombinesliteraltextandconversionspecifierstogenerateaformattedlogmessage.Theconversionspecifiersareletters(likec)thathavespecialmeaningsasplaceholders.Forexample,thelettersmayrepresentdatesorloggernames.
The%characterprecedestheconversionpatternsymbols.Forexample,considerthefollowingpattern:
Logger:%c{1}
Thistranslatesto"theliteraltext`Logger:'followedbythelogger'sname."Thenumber1incurlybraces({1})followingthe%ccharactersisaprecisionspecifier,whichmeans"displayjustonesegmentofthenamebeginningfromtherighthandside."Iftheloggeriscom.jspservletcookbook.LoggerServlet,thenthe%c{1}patterndisplays"LoggerServlet"inthelogtext.Thisisbecausethecconversionspecifierisaplaceholderfortheloggername.
Thelettermdisplaysthelogmessageitself,theletternproducestheplatform-specificlineseparator,andtheletterdrepresentsthedate.Theentirestring%d{ISO8601}isalog4jdateformatter,whichdisplaysthedateindetailedform.Seehttp://jakarta.apache.org/log4j/docs/api/org/apache/log4j/helpers/ISO8601DateFormat.html
Example14.8showsaservletthatusesaloggerthatinheritsitscharacteristicsfromtwoconfiguredloggers:therootloggerandthecom.jspservletcookbooklogger.
Example14-8.Aservletusesadescendantlogger
packagecom.jspservletcookbook;
importorg.apache.log4j.Logger;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassLoggerNewConfigextendsHttpServlet{
privateLoggerlog=null;
publicvoidinit(){
//thelogger'snameisthesameastheclassname:
//com.jspservletcookbook.LoggerNewConfig
log=Logger.getLogger(LoggerNewConfig.class);
log.info("LoggerNewConfigstarted.");
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//displayaDEBUG-levelmessage
log.debug("SendingaDEBUGmessage");
//displayanINFO-levelmessage
log.info("SendinganINFOmessage");
//betterdisplaysomeHTML
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Servletlogging</title></head><body>");
out.println(
"<h2>HellofromaLoggerwithitsownconfigurationinthe"+
log4j.propertiesfile</h2>");
out.println("Yourloggernameis:"+log.getName()+"<br>");
out.println(
"Yourloggerparentis:"+log.getParent().getName()+"<br>");
out.println("</body></html>");
}//enddoGet
}
Thestaticorg.apache.log4j.Logger.getLogger(ClassclassName)methodcreatesaloggernamedaftertheclassinExample14.8(com.jspservletcookbook.LoggerNewConfig).Therefore,thisnewloggerinheritstheappenderthatthepropertiesfileinExample14-7setupfortheloggercom.jspservletcookbook,becausethenewlogger'snamehascom.jspservletcookbookasaprefix.Infact,anyotherloggercreatedinclassesthatarepartofthecom.jspservletcookbookpackageinheritstheseproperties,aslongasthedeveloperkeepsnamingherloggersaftertheJavaclassinwhichtheyarecreated.
HereisanexampleofwhattheentirepatterntheconfigurationfileofExample14-7createdgeneratesinthelogfile:
INFOLogger:LoggerNewConfigDate:2003-07-1017:16:22,713-LoggerNewConfigstarted
DEBUGLogger:LoggerNewConfigDate:2003-07-1017:16:34,530-SendingaDEBUGmessage
INFOLogger:LoggerNewConfigDate:2003-07-1017:16:34,530-SendinganINFOmessage
Visithttp://jakarta.apache.org/log4j/docs/api/org/apache/log4j/PatternLayout.htmlformoredetailsonpatternlayouts.
Becauseoftheinheritancestructureestablishedbythelog4jconfigurationfile,theservletinExample14-8alsologsitsmessagestotheconsole.
SeeAlso
Recipe14.2ondownloadingandsettinguplog4j;Recipe14.3onusingalog4jloggerwithoutapropertiesfile;Recipe14.4onaddinganappendertotherootlogger;Recipe14.6onusingloggersinJSPs;Recipe14.7andRecipe14.8onusinglog4jwithapplicationeventlisteners;thelog4jdownloadsite:http://jakarta.apache.org/log4j/docs/download.html;thelog4jJavadocpage:http://jakarta.apache.org/log4j/docs/api/index.html;thelog4jprojectdocumentationpage:http://jakarta.apache.org/log4j/docs/documentation.html.
Recipe14.6Usinglog4jinaJSP
Problem
YouwanttoincludeloggingstatementsinaJSP.
Solution
Designacustomtagthatuseslog4jtoinitiateloggingmessages.
Discussion
AcustomtagisanXMLelementthatyouinventordesignforuseinaJSP.Inotherwords,theJSPcontainerdoesnotprovidethecustomactions;thewebdeveloperhimselfdesignstheJavaclassesthatprovidethetagfunctionality.Acustomtagoractioncanbeusedtoimplementlog4jloggingfunctionalityinJSPs.
Inthisrecipe,Ishow:
AJavaclassthatprovidesthetaghandlerforacustomtagnamedcbck:log.
ATagLibraryDescriptor(TLD)thatprovidesthewebapplicationwithinformationaboutthetag.
AJSPpagethatusesthecbck:logtag.
Example14-9showstheJavaclassLoggerTagonwhichthecbck:logtagisbased.Eachcustomactionisactuallydrivenbehindthe
scenesbyoneormoreJavaclasses.Inthiscase,LoggerTagislikeaJavaBeanthatwrapsthelog4jclasses,whichweimportatthetopofthetagclass.
CustomJSPactionsareacomplextopic,soIexplainthistagbyfocusingmainlyonitslog4jfeatures.SeeChapter22tohelpfillinthemissingspacesinyourownknowledgeaboutcustomtagdevelopment.
Example14-9.Acustomtagthatuseslog4j
packagecom.jspservletcookbook;
importorg.apache.log4j.Logger;
importorg.apache.log4j.PropertyConfigurator;
importjava.lang.reflect.Method;
importjavax.servlet.jsp.*;
importjavax.servlet.jsp.tagext.*;
publicclassLoggerTagextendsBodyTagSupport{
privateLoggerlog=null;
privateStringconfigFile=null;
privateStringlevel=null;
privatestaticfinalString[]LEVELS=
{"debug","info","warn","error","fatal"};
publicvoidsetConfigFile(StringfileName){
this.configFile=fileName;
}
publicvoidsetLevel(Stringlevel){
this.level=level;
}
publicintdoEndTag()throwsJspException{
StringrealPath=pageContext.getServletContext().getRealPath("/");
StringfileSep=System.getProperty("file.separator");
if(realPath!=null&&(!realPath.endsWith(fileSep))){
realPath=realPath+fileSep;}
//configuretheloggeriftheuserprovidesthisoptionalattribute
if(configFile!=null)
PropertyConfigurator.configure(realPath+
"WEB-INF/classes/"+configFile);
//throwanexceptionifthetaguserprovidesaninvalidlevel,
//somethingotherthanDEBUG,INFO,WARN,ERROR,orFATAL
level=level.toLowerCase();
if(!contains(level))
thrownewJspException(
"Thevaluegivenforthelevelattributeisinvalid.");
//Theloggerhasthesamenameastheclass:
//com.jspservletcookbook.LoggerTag.Therefore,itinheritsits
//appendersfromaloggerdefinedintheconfigfile:
//com.jspservletcookbook
log=Logger.getLogger(LoggerTag.class);
Stringmessage=getBodyContent().getString().trim();
Methodmethod=null;
try{
method=log.getClass().
getMethod(level,newClass[]{Object.class});
method.invoke(log,newString[]{message});
}catch(Exceptione){}
returnEVAL_PAGE;
}//doEndTag
publicvoidrelease(){
//releaseresourcesusedbyinstancevariables
log=null;
configFile=null;
level=null;
}//release
privatebooleancontains(Stringstr){
for(inti=0;i<LEVELS.length;i++){
if(LEVELS[i].equals(str))
returntrue;
}
returnfalse;
}//contains
}
TheLoggerTagextendsthejavax.servlet.jsp.tagext.BodyTagSupportclass,whichisdesignedforcustomactionsthatprocessbodycontent,orthetextthatmayappearbetweenopeningandclosingtags.
Thetagattributes,arequiredattributenamedlevelandtheconfigFileoptionalattribute,arehandledlikeJavaBeanproperties:
with"setter"methods(e.g.,publicvoidsetLevel(Stringlevel)).ThedoEndTag()methoddoesmostoftheimportantworkforthetag:
1. ItattemptstoconfiguretheloggeriftheuserhasprovidedaconfigurationfilenameintheconfigFileattribute.
Itchecksifthelevelisvalid(oneofDEBUG,INFO,WARN,ERROR,orFATAL).
Itlogsthemessage.
Example14-10showstheTLD,whichconveystagspecificstotheJSPcontainer,suchaswhetheranattributeisrequiredoroptional.ThetaglibraryassociatedwiththisTLDdescribesonlythecbck:logtag.TheTLDfilesmustbelocatedinWEB-INForasubdirectorythereof,orinsideoftheMETA-INFdirectoryofaJARthatisplacedinWEB-INF/lib.
Example14-10.TheTLDforthecustomloggertag
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEtaglib
PUBLIC"-//SunMicrosystems,Inc.//DTDJSPTagLibrary1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>cbck</short-name>
<uri>jspservletcookbook.com.tags</uri>
<description>Cookbookcustomtags</description>
<tag>
<name>log</name>
<tag-class>com.jspservletcookbook.LoggerTag</tag-class>
<body-content>JSP</body-content>
<description>Thistaguseslog4jtologamessage.</description>
<attribute>
<name>configFile</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<description>
Thisattributeprovidesanyconfigurationfilenameforthe
logger.Thefilemustbelocatedin
WEB-INF/classes.
</description>
</attribute>
<attribute>
<name>level</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
<description>Thisattributeprovidesthelevelforthelogrequest.
</description>
</attribute>
</tag>
</taglib>
Example14-11showsthelogger.jsppageandhowthecustomactioncanbeused.
Example14-11.AJSPusesalogcustomactiontoaccesslog4j
<%@pagecontentType="text/html"%>
<%@tagliburi="jspservletcookbook.com.tags"prefix="cbck"%>
<html>
<head><title>AloggingJSP</title></head>
<body>
<h2>Hereistheloggingstatement</h2>
<cbck:loglevel="debug">
Debugmessagefromlogger.jsp
</cbck:log>
Debugmessagefromlogger.jsp
</body>
</html>
First,thepageusesthetaglibdirectivetodeclarethetaglibrarythatcontainsourcustomaction.Example14-10showstheTLDfile,anXMLfilethatdescribesthepropertiesofataglibrary'svarioustags.Chapter22describesTLDsinmoredetail.
Thecbck:logcustomactionallowsadevelopertologamessagefromtheJSPbynestingthemessagetextwithinthecbck:logtag(i.e.,thebodycontentofthetagisthelogmessage).Thecbckpartofthetagistheprefixthatthetaglibdirectivedeclared.Thelogpartisthenameofthetag.Thetagallowsthedevelopertodeclarethelogginglevelwiththecustomaction'slevelattribute.
Typically,acomponentsuchasaninitializationservletinitializesthelog4jloggingsystemwhenthewebapplicationstartsup.Thecustomactiondescribedheredoesnothavetoinitializelog4jitself.However,I'veincludedanoptionalconfigFileattributethatpermitsmetospecifythenameofalog4jconfigurationfile,whichwillconfigurethelogger'slevel,appender(s),andlayout.
Forthistag,assumethatyouwanttodecidewhichloggingleveltouse,andthuspassinavalueforthelevelattribute.ThetagclassdoesnotknowwhetherthemessagewillrequestalogginglevelofDEBUG,INFO,WARN,ERROR,orFATAL.Sincethelogger'smethodsinlog4jusethesamenameasthelevels,wecandynamicallycallthepropermethod
basedonthevalueofthelevelattribute.Thisisthepurposeofthecode:
method=log.getClass().
getMethod(level,newClass[]{Object.class});
method.invoke(log,newString[]{message});
Wegetajava.lang.reflect.MethodobjectthatisnamedeitherDEBUG,INFO,WARN,ERROR,orFATAL,andtheninvokethatmethodcallingmethod.invoke,passinginthelogmessagefromtheJSPpage.
Aconfigurationfilenameisnotrequiredforthistag,sohowdoeslog4jknowhowandwheretologthemessage?Thistagassumesthataservlethasalreadyinitializedthelog4jsystemforthewebapplication,whichistypicalfortheuseoflog4jinawebenvironment.TheconfigurationfileistheonedescribedbyRecipe14.4andshowninExample14-5.
Youcanalsouseaservletasanlog4j-initializationservlet,similartoExample14-6.
Thatconfigurationfilecreatedaloggingmechanismthatsendsmessagestotheconsoleandafile,sothatiswherethecustomtag'smessagesgo.Forexample,runninglogger.jspdisplaysamessageontheconsole:
DEBUG-Debugmessagefromlogger.jsp
Thetag'sloggerwritesthefollowingmessageinthefileexample.log:
DEBUGLogger:LoggerTagDate:2003-05-1212:53:13,750-Debugmessagefromlogger.jsp
Ifyouwanttoincludeyourownconfigurationfile,youcanincludea
configFileattributewhenusingthecustomtag.Thetagwillconfiguretheloggerusingthatfileinsteadofanypreviouslyinitializedone:
if(configFile!=null)
PropertyConfigurator.configure(
pageContext.getServletContext().getRealPath("/")+
"WEB-INF/classes/"+configFile);
ThePropertyConfigurator.configure()methodallowsyoutospecifythenameofalog4jpropertiesfilewhenyouinitializetheloggingsystem,ifthefilenameisdifferentthanlog4j.properties.ThePropertyConfigurator.configure()method(inlog4jVersion1.2.8)doesnotthrowanexceptionthatcanbecaughtinthetagclass.YoucouldcheckfortheexistenceoftheconfigFilevalue(representingthepathtoafileinthewebapplication)explicitlyinthecodeusingthejava.ioAPI,andthenthrowanexceptioniftheconfigFileattributedeclaresaninvalidfilename.
SeeAlso
Recipe14.2ondownloadingandsettinguplog4j;Recipe14.3onusingalog4jloggerwithoutapropertiesfile;Recipe14.4onaddinganappendertotherootlogger;Recipe14.5onusingapatternlayoutwithalogger'sappender;Recipe14.7andRecipe14.8onusinglog4jwithapplicationeventlisteners;thelog4jdownloadsite:http://jakarta.apache.org/log4j/docs/download.html;thelog4jJavadocpage:http://jakarta.apache.org/log4j/docs/api/index.html;thelog4jprojectdocumentationpage:http://jakarta.apache.org/log4j/docs/documentation.html.
Recipe14.7LoggingMessagesUsingaServletContextEventListener
Problem
Youwanttologmessagesusinglog4jwhenaservletcontextiscreatedandshutdown.
Solution
Uselog4jandaservletcontexteventlistener.
Discussion
TheservletAPIincludesalistenerinterfacenamedjavax.servlet.ServletContextListenerthatyoucanusetonotifyaspecificJavaclasswhenaservletcontextiscreatedorshutdown.Thisnotifiedclassmaywanttologtheservletcontextcreationorshutdownorstoreanobjectattributeintheservletcontext,actionsthattheJavaclass(thelistener)takeswhenitreceivesitsnotification.
Theservletcontextlistenerisanapplicationeventlistener,acategorythatalsoincludessessioneventlisteners(seeChapter11orRecipe14.8)andrequesteventlisteners.Forexample,thesessioneventlistenerreceivesnotificationswhentheservletcontainercreatesnewHTTPsessionobjectsinordertotrackauser'sprogressthroughawebapplication.Theservletcontainernotifiestherequesteventlistenerwhenausermakesawebapplicationrequest,sothatalistenercantakesomekindofactionsuchasloggingtheuser'sIPaddress.
Ajavax.servlet.ServletContextisusedtostoreattributesor
accesscontextparametersthatarecommontoawebapplication,getRequestDispatcherobjectsforforwardingorincludingfiles(seeChapter6),orgetinformationsuchasanabsolutepathnameassociatedwithawebresource.Everywebapplicationhasoneassociatedservletcontext.
Thereisoneservletcontextinstanceperwebapplication(perJavaVirtualMachine(JVM),inthecaseofdistributedwebapplications)accordingtotheServletContextJavadoc:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletContext.html.
log4jisagoodchoiceforgeneratingcustom-designedlogmessagesfromaclassthatimplementstheServletContextListenerinterface.Example14-12showstheContextLoggerclass,whichuseslog4jtosendmessagesinitstwomethods.
Example14-12.Aservletcontexteventlistenerthatsendslogmessages
packagecom.jspservletcookbook;
importorg.apache.log4j.Logger;
importorg.apache.log4j.PropertyConfigurator;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassContextLoggerimplementsServletContextListener{
privateLoggerlog;
publicContextLogger(){}
publicvoidcontextDestroyed(ServletContextEventsce){
Stringname=sce.getServletContext().getServletContextName();
//logrequestoftheINFOlevel
log.info("ServletContextshutdown:"+(name==null?"":name));
//doothernecessarywork,likecleanupanyleft-overresources
//usedbythewebapp
}
publicvoidcontextInitialized(ServletContextEventsce){
ServletContextcontext=sce.getServletContext();
StringrealPath=context.getRealPath("/");
StringfileSep=System.getProperty("file.separator");
//Makesuretherealpathendswithafileseparatorcharacter('/')
if(realPath!=null&&(!realPath.endsWith(fileSep))){
realPath=realPath+fileSep;}
//Initializeloggerhere;thelog4jpropertiesfilenameisspecified
//byacontextparameternamed"logger-config"
PropertyConfigurator.configure(realPath+
"WEB-INF/classes/"+context.getInitParameter("logger-config"));
log=Logger.getLogger(ContextLogger.class);
Stringname=context.getServletContextName();
//logrequestaboutservletcontextbeinginitialized
log.info("ServletContextready:"+(name==null?"":name));
}
}
Givethisclassano-argsconstructor,placeitinWEB-INF/classesorinaJARlocatedinWEB-INF/lib,andregisteritinweb.xml:
<listener>
<listener-class>
com.jspservletcookbook.ContextLogger
</listener-class>
</listener>
TheServletContextListenertracksthelifecycleofaservletcontextwithtwomethods:contextInitialized()andcontextDestroyed().Theservletcontainercallsthefirstmethodwhentheservletcontextiscreatedandthewebapplicationisreadytoreceiveitsfirstrequest.ThecontainernotifiesthelistenerclassandcallsthecontextDestroyed()methodwhentheservletcontextisabouttobeshutdown,suchaswhenawebapplicationisstoppedpriortobeingreloaded.
Tomcat4.1.24initializestheservletcontextlistenerpriortocreatingservletinstances,eveniftheapplicationconfigurestheservlettobepreloaded.Example14-12initializesthelog4jsysteminthecontextInitialized()method.
Thedeploymentdescriptorcaninstructtheservletcontainertoloadaservletinstanceandcallitsinit()methodatstartupbyincludingaload-on-startupelementnestedintheservletelement,asin:
<servlet>
<servlet-name>logger</servlet-name>
<servlet-class>
com.jspservletcookbook.LoggerServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Thevalueofload-on-startupisanintegerindicatingtheorderinwhichthecontainerloadstheservlet.
InthecontextInitialized()method,thelistenerconfigureslog4jusingthefilespecifiedbyacontext-paramelementinweb.xml:
<context-param>
<param-name>logger-config</param-name>
<param-value>servletLog.properties</param-value>
</context-param>
Thislog4jconfigurationfile(servletLog.properties)islocatedintheWEB-INF/classesdirectory.Thelistenerthenlogsitsmessagestotheconsoleandtoafilewhenthewebapplicationstartsuporisshutdown.Example14-13showstheconfigurationfilethelistenerusesforlog4j.
Example14-13.Log4jconfigurationfileusedbytheservletcontextlistener
log4j.rootLogger=DEBUG,cons
log4j.logger.com.jspservletcookbook=,myAppender
log4j.appender.cons=org.apache.log4j.ConsoleAppender
#configurethe'myAppender'appender
log4j.appender.myAppender=org.apache.log4j.RollingFileAppender
log4j.appender.myAppender.File=h:/home/example.log
log4j.appender.myAppender.MaxBackupIndex=1
log4j.appender.myAppender.MaxFileSize=1MB
log4j.appender.cons.layout=org.apache.log4j.SimpleLayout
log4j.appender.myAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.myAppender.layout.ConversionPattern=
%-5pLogger:%c{1}Date:%d{ISO8601}-%m%n
Thelistenergetsaloggerwiththiscode:
log=Logger.getLogger(ContextLogger.class);
Thisnamestheloggeraftertheclasscom.jspservletcookbook.ContextLogger.Therefore,inthelog4jnamingscheme,thelistener'sloggerinheritstheappenderthatExample14-13definesfortheloggercom.jspservletcokbook.Thisisbecausetheconfigurationdoesnotdefinealoggerforcom.jspservletcookbook.ContextLogger;consequently,thelistener'sloggerinheritsthenextdefinedloggeravailable:com.jspservletcookbook.Thecom.jspservletcookbookloggerhasaconsoleappenderandafileappender.
Asaresult,theservletcontextlistenersendsitslogmessagestotheconsoleandtheh:/home/example.logfile.Example14-13hasdifferentlayoutsfortheconsoleandfileappenders.Thelistener'sconsolemessageslooklikethis:
INFO-ServletContextshutdown:Thehomewebapplication
INFO-ServletContextready:Thehomewebapplication
Thelogfilemessageshaveadifferentformat:
INFOLogger:ContextLoggerDate:2003-05-1216:45:20,398-ServletContextshutdown:
Thehomewebapplication
INFOLogger:ContextLoggerDate:2003-05-1216:45:20,999-ServletContextready:The
homewebapplication
Theformatofthesemessagesconsistsofthenameofthelogginglevel(e.g.,INFO),theloggername,thedateofthelogrequest,andthemessageitself.
SeeAlso
Recipe14.2ondownloadingandsettinguplog4j;Recipe14.3onusingalog4jloggerwithoutapropertiesfile;Recipe14.4onaddinganappendertotherootlogger;Recipe14.5onusingapatternlayoutwithalogger's
appender;Recipe14.6onusingaloggerwithaJSP;Recipe14.8onusinglog4jwithsessioneventlisteners;thelog4jdownloadsite:http://jakarta.apache.org/log4j/docs/download.html;thelog4jJavadocpage:http://jakarta.apache.org/log4j/docs/api/index.html;thelog4jprojectdocumentationpage:http://jakarta.apache.org/log4j/docs/documentation.html.
Recipe14.8LoggingMessagesUsingaSessionEventListener
Problem
Youwanttologmessagesinacustom-designedmannerfromasessioneventlistener.
Solution
Designasessioneventlistenerthatusesalog4jloggingmechanism.
Discussion
TheservletcontainernotifiesasessioneventlistenerclasswhenitcreatesanewHttpSession,aswellaswhenitisabouttoinvalidateorexpireasession.Webapplicationsusesessionstotrackauser'sprogressthroughthewebapplication,typicallybyidentifyinghimwithacookienamedJSESSIONID.SeeChapter10formoreinformationoncookies,andChapter11fordetailedcoverageofsessions.
Example14-14implementsthejavax.servlet.http.HttpSessionListenerinterfaceandtheinterface'stwomethods:sessionCreated()andsessionDestroyed().ThecodelogsmessagesrelatingtonewsessionsinsessionCreated()andrelatingtoinvalidatedsessionsinsessionDestroyed().
Example14-14.Usinglog4jinasessioneventlistener
packagecom.jspservletcookbook;
importorg.apache.log4j.Logger;
importorg.apache.log4j.PropertyConfigurator;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSessionLoggerimplementsHttpSessionListener
{
privateLoggerlog;
publicSessionLogger(){
/*
Theloggersaretypicallyinitializedbyaspecialinitialization
listenerorservlet.Ifthisisnotthecase,theninitializethe
loggerhere:
java.util.ResourceBundlebundle=
java.util.ResourceBundle.getBundle(
"com.jspservletcookbook.global");
PropertyConfigurator.configure(bundle.getString(
"log-configure-path"));
*/
log=Logger.getLogger(SessionLogger.class);
}
publicvoidsessionCreated(HttpSessionEventse){
//logrequestoftheINFOlevel
log.info("HttpSessioncreated:"+se.getSession().getId());
}
publicvoidsessionDestroyed(HttpSessionEventse){
//logrequestaboutsessionsthatareinvalidated
log.info("HttpSessioninvalidated:"+se.getSession().getId());
}
}
Givethisclassano-argsconstructor,placeitinWEB-INF/classesorinaJARlocatedinWEB-INF/lib,andregisteritinweb.xml:
<listener>
<listener-class>
com.jspservletcookbook.SessionLogger
</listener-class>
</listener>
TheSessionLoggerclassgetsaloggerinitsconstructor;itdependsontheapplicationalreadyhavinginitializedthelog4jloggingmechanisminaservletorintheservletcontextlistener(asinRecipe14.4).
Awebapplicationcanconfigureitslog4jmechanismusingaspecialinitializationservletorlistener,sotheotherclassesorbeansthatdologgingdonothavetohandlethelog4jconfigurationstage.Youcaninitializethelog4jloggingmechanismusingaservletsuchastheoneshowninRecipe14.6.
Thecommented-outcodeintheconstructorshowsanotherwaythatthislistenerclasscouldconfigureitsownloggerintheeventthattheapplicationhasnotyetconfiguredtheloggingmechanism.
HereisthemessageloggedtotheTomcatconsoleafterthefirstrequesttoaservletorJSPthatparticipatesinsessiontracking:
INFO-HttpSessioncreated:A65481C53B92F869BD18961D635BBF52
Whenthesessionisinvalidated,theconsoletextis:
INFO-HttpSessioninvalidated:A65481C53B92F869BD18961D635BBF52
LikethelistenerdescribedinRecipe14.7,thesessionlistener'sloggerinheritstheloggingdestinationsorappendersfromthecom.jspservletcookbooklogger.TheconfigurationfileofExample14-13showshowthisloggerissetuptosendmessagestoboththeconsoleandanexample.logfile.Thelogfile'sappenderlayoutisspecifiedusingaPatternLayout,whichisadifferentlayoutthantheoneusedwiththeconsoleappender.Hereisexampletextfromthislogwhentheservletcontainerinvalidatesasession:
INFOLogger:SessionLoggerDate:2003-05-1220:41:05,367-HttpSessioninvalidated:
A65481C53B92F869BD18961D635BBF52
SeeAlso
Recipe14.2ondownloadingandsettinguplog4j;Recipe14.3onusingalog4jloggerwithoutapropertiesfile;Recipe14.4onaddinganappendertotherootlogger;Recipe14.5onusingapatternlayoutwithalogger'sappender;Recipe14.6onusingaloggerwithaJSP;Recipe14.8onusinglog4jwithsessioneventlisteners;thelog4jdownloadsite:http://jakarta.apache.org/log4j/docs/download.html;thelog4jJavadocpage:http://jakarta.apache.org/log4j/docs/api/index.html;thelog4jprojectdocumentationpage:http://jakarta.apache.org/log4j/docs/documentation.html.
Chapter15.AuthenticatingClientsIntroduction
Recipe15.1.CreatingUsersandPasswordswithTomcat
Recipe15.2.SettingUpSSLonTomcat
Recipe15.3.UsingBASICAuthentication
Recipe15.4.UsingForm-BasedAuthentication
Recipe15.5.LoggingOutaUser
Recipe15.6.UsingJAAStoCreateaLoginModule
Recipe15.7.CreatingtheJAASConfigurationFile
Recipe15.8.UsingJAASinaServlet
Recipe15.9.UsingJAASinaJSP
Introduction
Becauseoftheincreaseindigitalcommerceandacorrespondingriseintheneedtotransferandstoresensitivedata(suchascreditcardnumbersandfinancialaccounts),securityisofparamountimportancetoJavawebapplications.
Thischapter'srecipescovertasksthatinvolveauthentication,whichisdesignedtoanswerthequestion"areyouwhoyousayyouare?"Authenticationusuallyinvolvesaninteractionbetweenaclientoruserandserver-sidecodeforthepurposeofcheckingausernameandpassword(andsometimesadigitalcertificate,biometricdata,orotherevidence)againststoredinformation,suchasauserdatabase.
TherecipesdescribehowtosetupSecureSocketsLayer(SSL),aswellasuseBASIC-andform-basedauthenticationwithApacheTomcat.ThelaterrecipesdescribehowtouseapowerfulsecurityframeworkcalledJavaAuthenticationandAuthorizationService(JAAS)withservletsandJSPs.
Recipe15.1CreatingUsersandPasswordswithTomcat
Problem
Youwanttocreateusernamesandpasswordsforauthenticatingrequestsforcertainwebcomponents.
Solution
Addtheusernames,passwords,androlestothetomcat-users.xmlfile.
Discussion
AveryeasymethodofauthenticatinguserswithTomcatinvolvescreatingusernames,passwords,androlesinthetomcat-users.xmlfile.Thisfileisstoredin<Tomcat-installation-directory>/conf.
Everyoneisfamiliarwithusernamesandpasswords,butwhatareroles?Rolesarelogicalwaystodescribegroupsofuserswhohavesimilarresponsibilities,suchasmanagerordatabaseAdmin.Example15-1showsatomcat-users.xmlfilethatcreatestworolesandtwouserswithtwoaptlynamedXMLelements:roleanduser.
Example15-1.Thetomcat-usersXMLfile
<?xmlversion='1.0'encoding='utf-8'?>
<tomcat-users>
<rolerolename="dbadmin"/>
<rolerolename="manager"/>
<userusername="BruceP"password="bwperry"roles="dbadmin,manager"/>
<userusername="JillH"password="jhayward"roles="manager"/>
</tomcat-users>
InExample15-1,theuserBrucePisassociatedwithtworoles(dbadminandmanager),whileuserJillHisassociatedonlywiththemanagerrole.TomcatusesthisfilewhenauthenticatinguserswithBASICandform-basedauthentication,asdescribedinRecipe15.3andRecipe15.4.
SeeAlso
TheTomcatdocumentationandRecipe15.2onsettingupSSLforusewithauthentication:http://jakarta.apache.org/tomcat/tomcat-4.1-doc/ssl-howto.html;Recipe3.9onrestrictingrequestsforcertainservlets;Recipe15.3onusingBASICauthentication;Recipe15.4onusingform-basedauthentication;Recipe15.5onloggingoutauser;Recipe15.6-Recipe15.9onusingJAAS.
Recipe15.2SettingUpSSLonTomcat
Problem
YouwanttosetupSSLonTomcatsothatyoucantransmitusernamesandpasswordsinencryptedform.
Solution
CreateadigitalcertificatefortheTomcatserverusingthe$JAVA_HOME\bin\keytoolutility,thenuncommenttheSSLConnectorelementinconf/server.xml.
Discussion
WhentransferringusernamesandpasswordsoverHTTP,youshouldsetupSSLonTomcatorwhicheverapplicationserveryouareusing.Thisprotocolensuresthatthenamesandpasswordsareinencryptedformastheytravelacrossthenetwork,andthusprotectedfromtheftandmalicioususebyhackersandotherintruders.
SettingupSSLonTomcat4isatwo-stepprocess:
1. Usethekeytoolutilitytocreateakeystorefileencapsulatingadigitalcertificateusedbytheserverforsecureconnections.
UncommenttheSSLConnectorelementinTomcat'sconf/server.xmlfile,andalteritsattributesifnecessary.
ThekeytoolutilityislocatedinthebinsubdirectoryofthedirectorywhereyouhaveinstalledtheJSDK.Thefollowingcommandlinecreates
asingleself-signeddigitalcertificatefortheTomcatserverwithinakeystorefilenamed.keystore.Thisfileiscreatedinthehomedirectoryoftheuserrunningthecommand.
%JAVA_HOME%\bin\keytool-genkey-aliastomcat-keyalgRSA
TheUnixversionofthiscommandis:
$JAVA_HOME\bin\keytool-genkey-aliastomcat-keyalgRSA
Forthiscommandtosucceed,theJAVA_HOMEenvironmentvariablemustbesettothedirectorywheretheJava2SDKisinstalled,suchash:\j2sdk1.4.1_01.
Example15-2showstheconsoleoutputresultingfromexecutingthekeytoolcommand.Thekeytoolwillrequestsomeinformationaboutyouandyourorganization,butyoucanacceptthedefaultvaluesbypressingEnter.Thisinformationisincorporatedintotheserver'scertificateandpresentedtotheuser(viaherwebbrowser)whensherequestsanycomponentswithaURLthatstartswithhttps://.
InsettingupSSLforTomcat,youmustusethesamepasswordforboththekeystoreandthecertificatethatisstoredinthekeystore.
ThedefaultpasswordusedinTomcatis"changeit":http://jakarta.apache.org/tomcat/tomcat-4.1-doc/ssl-howto.html.
Example15-2.Theconsoleoutputresultingfromusingthekeytoolutility
Enterkeystorepassword:changeit
Whatisyourfirstandlastname?
[Unknown]:BrucePerry
Whatisthenameofyourorganizationalunit?
[Unknown]:
Whatisthenameofyourorganization?
[Unknown]:
WhatisthenameofyourCityorLocality?
[Unknown]:
WhatisthenameofyourStateorProvince?
[Unknown]:
Whatisthetwo-lettercountrycodeforthisunit?
[Unknown]:
IsCN=BrucePerry,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknowncorrect?
[no]:yes
Enterkeypasswordfor<tomcat>
(RETURNifsameaskeystorepassword):
Finally,uncommenttheSSLConnectorelementintheconf/server.xmlfile(showninFigure15-3)byremovingthecommentcharactersaroundit(<!---->).ThenrestartTomcat.
Example15-3.TheConnectorelementinsideserver.xml
<!--DefineaSSLCoyoteHTTP/1.1Connectoronport8443-->
<ConnectorclassName=
"org.apache.coyote.tomcat4.CoyoteConnector"port=
"8443"minProcessors="5"maxProcessors="75"enableLookups=
"true"acceptCount="100"debug="0"scheme="https"secure="true"
useURIValidationHack="false"disableUploadTimeout="true">
<FactoryclassName=
"org.apache.coyote.tomcat4.CoyoteServerSocketFactory"clientAuth=
"false"protocol="TLS"/>
</Connector>
TheConnectorusesadifferentportnumber(8443)thanthatusedbyinsecureHTTPconnections(inTomcat,it'susually8080).AfteryouhaverestartedTomcat,youcannowmakeasecureconnectiontoawebcomponentinthehomeapplicationwithaURLthatlookslikethis:
https://localhost:8443/home/sqlJsp.jsp
Don'tforgetthehttps(asopposedtohttp)partinsettinguptheseweblinks!
SeeAlso
TheTomcatdocumentationonsettingupSSLforusewithauthentication:http://jakarta.apache.org/tomcat/tomcat-4.1-doc/ssl-howto.html;Recipe15.1oncreatingusernamesandpasswordsinTomcat;Recipe15.3onusingBASICauthentication;Recipe15.4onusingform-basedauthentication;Recipe15.5onloggingoutauser;Recipe15.6-Recipe15.9onusingtheJAAS.
Recipe15.3UsingBASICAuthentication
Problem
YouwanttouseBASICauthenticationwithwebcomponentsinaTomcatwebapplication.
Solution
Usethesecurity-constraint,login-config,andsecurity-roleelementsinthedeploymentdescriptortoprotectoneormoreURLs.
Discussion
BASICauthenticationisasecuritymethodthathasbeenusedwithwebresourcesforseveralyears,andallpopularbrowserssupportit.ThismethodofauthenticationinvolvesthetransferofusernamesandpasswordsoveranetworkencodedwiththeBase64content-encodingmechanism.Base64iseasytodecodeandthereforenotverysecure.ThesolutionistocombineBASICauthenticationwithSSL,whichwillfurtherencryptthedataasitistransferredacrossthenetwork(seeRecipe15.2).
HereishowsettingupBASICauthenticationworkswithwebapplicationsthatyouhaveinstalledonTomcat:
1. Setupusernames,passwords,androlesintheconf/tomcat-users.xmlfiledescribedinRecipe15.1.
Createasecurity-constraintelementinthedeployment
descriptor(web.xml),specifyingthewebresourcesforwhichyouarerequiringauthentication.
Includealogin-configinweb.xml;thiselementhasanestedauth-methodelementthatcontainsthetext"BASIC".
Whentheuserrequestsanyoftheprotectedresources,theserversendsalongaresponseheaderthatlookslikethis:
WWW-Authenticate:BASICRealm="MyRealm"
Youareprobablyfamiliarwithwhathappensnext:thebrowserdisplaysastandarddialogwindowrequestingtheclienttoprovideausernameandpassword(Figure15-1).Iftheusernameandpasswordareincorrect,thebrowserwilleithergivetheuseranotherchancetologinbyredisplayingthedialogwindow,orsimplysendbackaserverstatuscode"401:Unauthorized"typeofresponse.
Theusernamesandpasswordsintheconf/tomcat-users.xmlfilearecase-sensitive.Theuserhastotypethemintothedialogwindowusingupper-andlowercaselettersexactlyastheyappearinconf/tomcat-users.xml.
Example15-4showstheweb.xmlelementsthataredesignedtoinitiateBASICauthenticationfortheURLpattern/sqlJsp.jsp.
Example15-4.Asecurity-constraintinitiatesauthenticationwithaJSPfile
<!--Beginningofweb.xmldeploymentdescriptor-->
<security-constraint>
<web-resource-collection>
<web-resource-name>JSPdatabasecomponent</web-resource-name>
<url-pattern>/sqlJsp.jsp</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>dbadmin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>dbadmin</role-name>
</security-role>
<!--Restofweb.xmldeploymentdescriptor-->
Thesecurity-constraintelementinExample15-4containsaweb-resource-collectionelement.Thiselementspecifiesthefollowingconstraintsthatapplytoanyrequestsfor/sqlJsp.jsp:
TheconstraintsapplytoanyGETorPOSTrequests(asspecifiedbythehttp-methodelements).
Theauth-constraintelementnestedinsidesecurity-constraintcontainstherole-namedbadmin.Therefore,therequestormustentertheproperusernameandpassword(asspecifiedinthetomcat-users.xmlfile)andbeassociatedwiththedbadminrole.Onlythosewhohavethedbadminrolecangainaccesstotheprotectedwebresource,eveniftheyenteraproperusernameandpassword.
Figure15-1showsthedialogboxthatNetscape7.1produceswhenTomcatisusingBASICauthentication.TheURLisusedishttps://localhost:8443/home/sqlJsp.jsp.
Figure15-1.Abrowserdialogwindowrequestsanameandpassword
NoticethattheURLusesasecureconnectiontorequesttheJSP:anHTTPSprotocolandport8443onTomcat.
Figure15-2showsabrowserwindowafteraclienthasfailedauthentication.
Figure15-2.Aserverstatuscode401pageasviewedinthewebbrowser
SeeAlso
TheTomcatdocumentationandRecipe15.2onsettingupSSLforusewithauthentication:http://jakarta.apache.org/tomcat/tomcat-4.1-doc/ssl-howto.html;Recipe3.9onrestrictingrequestsforcertainservlets;Recipe15.5onloggingoutauser;Recipe15.6-Recipe15.9onusingJAAS.
Recipe15.4UsingForm-BasedAuthentication
Problem
Youwanttodesignyourownformtoreceivetheuser'snameandpasswordduringBASICauthentication.
Solution
Usethelogin-configelementinthedeploymentdescriptorandgiveitsnestedauth-methodelementavalueof"FORM".
Discussion
TheservletAPIoffersanalternativetousingplain-vanillaBASICauthentication:form-basedauthentication.Thismethodallowsyoutodesignyourownformforreceivingtheuser'snameandpassword,aswellasspecifyingtheinformativepagethattheserverssendtotheclientiftheuser'sauthenticationfails.ThisgivesyoutheabilitytoprovideamuchmorefriendlyandcustomizeduserinterfaceforapplicationsinvolvingBASICauthentication.
Theform-basedmethodshouldstillbecombinedwithSSLandtheHTTPSprotocolsothatthenamesandpasswordsareencryptedastheytravelthroughthenetwork.
Example15-5showstheform-basedsetupforthewebapplication'sdeploymentdescriptor.ItdiffersfromRecipe15.3ssetupinonearea:the
login-configelement,whichisemphasizedinthefollowingcodesample.
Example15-5.Theweb.xmlelementsdesignedforform-basedauthentication
<!--Beginningofweb.xmldeploymentdescriptor-->
<security-constraint>
<web-resource-collection>
<web-resource-name>JSPdatabasecomponent</web-resource-name>
<url-pattern>/sqlJsp.jsp</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>dbadmin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/loginError.jsp</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>dbadmin</role-name>
</security-role>
<!--Restofweb.xmldeploymentdescriptor-->
Theauth-methodelementincludesthetext"FORM".Theform-login-configelementspecifiesthelogin(/login.html)andauthenticationfailurepage(/loginError.html)thatyourapplicationuses.Theforwardslash(/)precedingthefilenamesmeanstonavigatetothepagefromthewebapplication'srootdirectory.
Almostbymagic,ifauserrequestsaprotectedresourceinyourapplication,theserversendshimthelogin.htmlpage(inthisexample)insteadofinitiatingthetypicalbehaviorinwhichthebrowserdisplaysitsowndialogwindow.Ifthenameandpasswordtheuserentersturnsouttobeincorrect,theserverrouteshisrequesttotheloginError.htmlpage.
Example15-6showsthelogin.htmlpage,forreference.
Example15-6.Theloginform
<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.0Transitional//EN">
<html>
<head>
<title>Welcome</title>
</head>
<bodybgcolor="#ffffff">
<h2>PleaseLogintotheApplication</h2>
<formmethod="POST"action="j_security_check">
<tableborder="0"><tr>
<td>Entertheusername:</td><td>
<inputtype="text"name="j_username"size="15">
</td>
</tr>
<tr>
<td>Enterthepassword:</td><td>
<inputtype="password"name="j_password"size="15">
</td>
</tr>
<tr>
<td><inputtype="submit"value="Submit"></td>
</tr>
</table>
</form>
</body>
</html>
Figure15-3showswhatthisformlookslikeinawebbrowser.
Figure15-3.Aformforusewithform-basedauthentication
Withform-basedauthentication,theformtag'sactionattributemusthavethevalue"j_security_check".Theinputelementsfortheusernameandpasswordmustspecifythevalues"j_user_name"and"j_password",respectively,fortheirnameattributes.
Figure15-4showstheHTMLpagethattheserversendstheuserifherauthenticationfails.
Figure15-4.Form-basedauthenticationallowstheinclusionofyourownlogin-failurepage
Example15-7showsthesourceforthispage.Theform-basedapproachismorepredictableandfriendlierthanthevariousbrowsers'methodsfordealingwithBASICauthentication.
Example15-7.TheserverdisplaystheloginError.jsppagewhenauthenticationfails
<html>
<head>
<title>LoginError</title>
</head>
<bodybgcolor="#ffffff">
<h2>WeApologize,ALoginErrorOccurred</h2>
Pleaseclick<ahref="http://localhost:8080/home/sqlJsp.jsp">here</a>foranothertry.
<%--Or,dynamicallylisthyperlinkstoyourprotectedresourceshere,perhapsbygetting
themfromadatabaseorconfigurationfile,insteadofhard-codingalinkintotheerror
page.--%>
</body>
</html>
SeeAlso
TheTomcatdocumentationandRecipe15.2onsettingupSSLforusewithauthentication:http://jakarta.apache.org/tomcat/tomcat-4.1-doc/ssl-howto.html;Recipe3.9onrestrictingrequestsforcertainservlets;Recipe15.5onloggingoutauser;Recipe15.6-Recipe15.9onusingJAAS.
Recipe15.5LoggingOutaUser
Problem
Youwanttologoutauserinasystemthatusesform-basedauthentication.
Solution
Callinvalidate()ontheuser'sHttpSessionobject.
Discussion
Invalidatingauser'sHttpSessionobjectwilllogtheuseroutinanapplicationthatusesform-basedauthentication.Naturally,thiscodeinvolvescallingHttpSession.invalidate().Example15-8displayssomeinformationaboutalogged-inuser,thenlogshimoutbyinvalidatinghissession.Thenexttimethisuserrequestsaprotectedresource,thewebapplicationwillsendhimtotheconfiguredloginpage,becausehehasbeenloggedoutoftheapplication.
Example15-8.Loggingoutauser
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassLogoutServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
HttpSessionsession=request.getSession();
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>AuthenticatedUserInfo</title></head><body>");
out.println("<h2>Loggingoutauser</h2>");
out.println("request.getRemoteUser()returns:");
//getthelogged-inuser'sname
StringremUser=request.getRemoteUser();
//Istherequest.getRemoteUser()returnvaluenull?If
//so,thentheuserisnotauthenticated
out.println(remUser==null?"Notauthenticated.":remUser);
out.println("<br>");
out.println("request.isUserInRole(\"dbadmin\")returns:");
//Findoutwhethertheuserisinthedbadminrole
booleanisInRole=request.isUserInRole("dbadmin");
out.println(isInRole);
out.println("<br>");
//logouttheuserbyinvalidatingtheHttpSession
session.invalidate();
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
doGet(request,response);
}//doPost
}//LogoutServlet
Alogged-inuserwhorequeststhisservletseestheoutputinFigure15-5.TheservletdisplaysthereturnvaluesofHttpServletRequest.getRemoteUser()(theusername)andHttpServletRequest.isUserInRole().Thelattermethodreturnsabooleanvalueindicatingwhethertheuserisassociatedwiththerolespecifiedbythemethod'sStringparameter.
Figure15-5.Aservletshowssomeuser-relatedinformationbeforeloggingouttheuser
Theservlettheninvalidatestheuser'ssessiontologherout.RerequestingtheservletproducestheoutputshowninFigure15-6.
Figure15-6.Theservlet'soutputindicatesalogged-outuser
SeeAlso
TheTomcatdocumentationandRecipe15.2onsettingupSSLforusewithauthentication:http://jakarta.apache.org/tomcat/tomcat-4.1-doc/ssl-howto.html;Recipe3.9onrestrictingrequestsforcertainservlets;Recipe15.6-Recipe15.9onusingJAAS.
Recipe15.6UsingJAAStoCreateaLoginModule
Problem
YouwanttousetheJavaAuthenticationandAuthorizationService(JAAS)tocreateanauthenticationmodulethataservletorJSPcanuse.
Solution
Createajavax.security.auth.spi.LoginModuleclassforyourapplication,thenstoretheclassunderWEB-INF/classesorWEB-INF/lib(inaJARfile).
Discussion
TheJAASisasecurityAPIthatcanbeusedtocreatestandalone,pluggableauthenticationorauthorizationtoolsforJavaapplications.PluggablemeansthattheJAASsecuritycodeisnotboundtoaparticularapplication;itisstoredinaJARfileandcanbedroppedorpluggedintowebapplicationsandothertypesofJavaprograms.
JAASisaJavaversionofaframeworknamedPluggableAuthenticationModule(PAM).Here'salinktoapaperonthatverytopic:http://java.sun.com/security/jaas/doc/pam.html.
Forthesakeofclarity,Recipe15.5-Recipe15.7describeasimple
exampleofJAASauthenticationthatrequirestwoclasses,andoneservletthatusestheJAASAPI.Inourexamples,theseclassesarestoredinWEB-INF/classes.However,manyorganizationshaveacomplexsecurityarchitecturethatcallsforamoreextensiveauthenticationandauthorizationmodel,andthusmoreJavacodeandobjects.Inthesecases,you'llwanttocreateaseparatepackagenameforyourJAAScode,archiveitinaJARfile,andplaceitinWEB-INF/libforwebapplicationstouse.
TakethefollowingstepstouseJAASforauthenticatingwebclients:
1. MakesureyouhaveinstalledtheJAASpackagesforusewithawebapplication.JAAShasbeenintegratedintotheJava21.4SDK,soyoucanuseJAASifTomcatoryourapplicationserverisusingthisversionofJava.SeethefollowingwebsiteifyouareusingJava1.3,whichrequiresyoutodownloadandinstallJAASasaJavaextension:http://java.sun.com/products/jaas/index-10.html.
CreateaLoginModuleclasstohandletheauthentication.ThisclassmustbestoredinWEB-INF/classesorinaJARfileplacedinWEB-INF/lib.
CreateaCallbackHandlerclassthatdealswithinteractionwiththeclienttogetitsusernameandpassword.StorethisclasswithyourLoginModule.
CreateaJAASconfigurationfilethatspecifieswhichLoginModule(s)youareusingforauthentication.PlacetheconfigurationfileinalocationwheretheJAAS-relatedcodecanreadit(seethedescriptionoftheconfigurationfileinRecipe15.7).
IncludeaLoginContextobjectinservletcodeandcallitslogin()method.
Authenticationcheckswhetherauserorclienthasaparticularidentity,whichis
typicallyoneofasetofusernamesandpasswords.JAAScanalsobeusedforauthorization,whichspecifiestheextentofaccesstodataauserhasoncesheissuccessfullyauthenticated.Thisrecipefocusessolelyonauthentication.
Inordertomakeclearerarathercomplexmatter,Ihavebrokenthesestepsupintothreerecipes:
Thisrecipedescribessteps1-3.
Recipe15.6showshowtocreatetheJAASconfigurationfile.
Recipe15.7usestheJAASauthenticationclassesinaservlet.
Example15-9showsaclassthatimplementsthejavax.security.auth.spi.LoginModuleinterface.Itperformsmostoftheworkinidentifyingclients,andusespackagesthatarepartoftheJAASAPI(emphasizedwithboldinthecodesample).YouhavetomakethisclassavailabletotheservletenginebyplacingitinWEB-INF/classesorinaJARfilestoredinWEB-INF/lib.
Example15-9.TheLoginModuleforwebauthentication
packagecom.jspservletcookbook;
importjava.util.Map;
importjava.sql.*;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.security.auth.spi.LoginModule;
importjavax.security.auth.*;
importjavax.security.auth.callback.*;
importjavax.security.auth.login.*;
importjavax.sql.*;
publicclassDataSourceLoginModuleimplementsLoginModule{
//Theseinstancevariableswillbeinitializedbythe
//initialize()method
CallbackHandlerhandler;
Subjectsubject;
MapsharedState;
Mapoptions;
privatebooleanloginPassed=false;
publicDataSourceLoginModule(){}//no-argumentsconstructor
publicvoidinitialize(Subjectsubject,CallbackHandlerhandler,
MapsharedState,Mapoptions){
this.subject=subject;
this.handler=handler;
this.sharedState=sharedState;
this.options=options;
}
publicbooleanlogin()throwsLoginException{
Stringname="";
Stringpass="";
Contextenv=null;
Connectionconn=null;
Statementstmt=null;
ResultSetrs=null;
DataSourcepool=null;
booleanpassed=false;
try{
//CreatetheCallBackarraytopasstothe
//CallbackHandler.handle()method
Callback[]callbacks=newCallback[2];
//Don'tusenullargumentswiththeNameCallbackconstructor!
callbacks[0]=newNameCallback("Username:");
//Don'tusenullargumentswithPasswordCallback!
callbacks[1]=newPasswordCallback("Password:",false);
handler.handle(callbacks);
//GettheusernameandpasswordfromtheCallBacks
NameCallbacknameCall=(NameCallback)callbacks[0];
name=nameCall.getName();
PasswordCallbackpassCall=(PasswordCallback)callbacks[1];
pass=newString(passCall.getPassword());
//LookupourDataSourcesothatwecanchecktheusernameand
//password
env=(Context)newInitialContext().lookup("java:comp/env");
pool=(DataSource)env.lookup("jdbc/oracle-8i-athletes");
if(pool==null)
thrownewLoginException(
"InitializingtheDataSourcefailed.");
//TheSQLforcheckinganameandpasswordinatablenamed
//athlete
Stringsql="select*fromathletewherename='"+name+"'";
Stringsqlpass="select*fromathletewherepasswrd='"+pass+"'";
//GetaConnectionfromtheconnectionpool
conn=pool.getConnection();
stmt=conn.createStatement();
//Checktheusername
rs=stmt.executeQuery(sql);
//IftheResultSethasrows,thentheusernamewas
//correctandnext()returnstrue
passed=rs.next();
rs.close();
if(!passed){
loginPassed=false;
thrownewFailedLoginException(
"Theusernamewasnotsuccessfullyauthenticated");
}
//Checkthepassword
rs=stmt.executeQuery(sqlpass);
passed=rs.next();
if(!passed){
loginPassed=false;
thrownewFailedLoginException(
"Thepasswordwasnotsuccessfullyauthenticated");
}else{
loginPassed=true;
returntrue;
}
}catch(Exceptione){
thrownewLoginException(e.getMessage());
}finally{
try{
//closetheStatement
stmt.close();
//ReturntheConnectiontothepool
conn.close();
}catch(SQLExceptionsqle){}
}//finally
}//login
publicbooleancommit()throwsLoginException{
//We'renotdoinganythingspecialhere,sincethisclass
//representsasimpleexampleofloginauthenticationwithJAAS.
//Justreturnwhatlogin()returned.
returnloginPassed;
}
publicbooleanabort()throwsLoginException{
//Resetstate
booleanbool=loginPassed;
loginPassed=false;
returnbool;
}
publicbooleanlogout()throwsLoginException{
//Resetstate
loginPassed=false;
returntrue;
}//logout
}//DataSourceLoginModule
AclassthatimplementsLoginModulehastoimplementtheinterface'sfivedeclaredmethods:initialize(),login(),commit(),abort(),andlogout().login()initiatesthemaintaskofcheckingtheusernameandpasswordanddeterminingwhethertosuccessfullyauthenticatetheclient.Sincethisisasimpleexample,theDataSourceLoginModulefocusesonthelogin()method.TheothermethodsinExample15-9simplyresettheobject'sstatesothatitcanperformanotherauthentication,althoughamorecomplexloginprocessinvolvesothertasks,suchassettingupauthorization-relatedobjectsfortheauthenticateduser.
JAASisaquitecomprehensiveframework.RefertoSunMicrosystems'documentation(http://java.sun.com/products/jaas/)forguidanceindevelopingmoreadvancedJAASprogramsthanthosedescribedinthisrecipe.
JAASseparatestheresponsibilityforinteractingwiththeclient(suchasgettingtheusernameandpassword)andperformingauthenticationintoCallbackHandlersandLoginModules,respectively.TheLoginModuleinExample15-9usesaCallbackHandlertogettheusernameandpassword,thenchecksthisinformationbyaccessingatablefromanOracle8idatabase.ThemoduleusesaJNDIlookuptogetaccesstothedatabase,whichChapter21explainsindetail.
Basically,theLoginModuleborrowsaConnectionfromadatabase-connectionpool,usesSQLSELECTstatementstochecktheclient'snameandpassword,thenreturnstheConnectiontothesharedpoolbyclosingit.
TheCallbackHandlerinExample15-10getstheclient'susernameandpasswordfromHTTPrequestparameters.Theclass'sconstructorincludesaServletRequestargument,fromwhichtheclasscanderiverequestparametersbycallingServletRequest'sgetParameter()method.Thisprocesswillbecomemuchclearerwhenyouseehowtheservlet(seeExample15-11inRecipe15.7)usestheseclassestoperformtheauthentication.
Example15-10.ACallbackHandlerforuseinwebauthentication
packagecom.jspservletcookbook;
importjavax.security.auth.callback.*;
importjavax.servlet.ServletRequest;
publicclassWebCallbackHandlerimplementsCallbackHandler{
privateStringuserName;
privateStringpassword;
publicWebCallbackHandler(ServletRequestrequest){
userName=request.getParameter("userName");
password=request.getParameter("password");
}
publicvoidhandle(Callback[]callbacks)throwsjava.io.IOException,
UnsupportedCallbackException{
//Addtheusernameandpasswordfromtherequestparametersto
//theCallbacks
for(inti=0;i<callbacks.length;i++){
if(callbacks[i]instanceofNameCallback){
NameCallbacknameCall=(NameCallback)callbacks[i];
nameCall.setName(userName);
}elseif(callbacks[i]instanceofPasswordCallback){
PasswordCallbackpassCall=(PasswordCallback)callbacks[i];
passCall.setPassword(password.toCharArray());
}else{
thrownewUnsupportedCallbackException(callbacks[i],
"TheCallBacksareunrecognizedinclass:"+getClass().
getName());
}
}//for
}//handle
}
JusttosummarizehowtheLoginModuleandCallbackHandlerfittogetherbeforeyoumoveontothenexttworecipes,oneoftheLoginContext'sconstructorstakesaCallbackHandlerasitssecondparameter,asinthefollowingcode:
WebCallbackHandlerwebcallback=newWebCallbackHandler(request);
LoginContextlcontext=null;
try{
lcontext=newLoginContext("WebLogin",webcallback);
}catch(LoginExceptionle){//respondtoexception...}
Recipe15.7showshowtocreateaJAASconfigurationfile,whichspecifiestheLoginModule(s)thatcertainapplicationswilluseduringauthentication.
SeeAlso
SunMicrosystems'JAASdeveloper'sguide:http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASLMDevGuide.htmlalistofJAAStutorialsandsampleprograms:http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.htmltheJavadocrelatingtoJAASconfigurationfiles:http://java.sun.com/j2se/1.4.1/docs/api/javax/security/auth/login/Configuration.htmlRecipe15.9onusingJAASwithaJSP.
Recipe15.7CreatingtheJAASConfigurationFile
Problem
YouwanttocreatetheJAASconfigurationfile.
Solution
Createtheconfigurationfile,thenspecifytheconfiguration'slocationonyourfilesysteminthe${java.home}/jre/lib/security/java.securityfile.
Discussion
UsingJAASalsoinvolveswritingaconfigurationfiletoidentifytheLoginModule(s)thataparticularapplicationwilluse.TheconfigurationfileinExample15-11specifiesanapplicationnamed"WebLogin."
Example15-11.AJAASconfigurationfile
WebLogin{
com.jspservletcookbook.DataSourceLoginModulerequisite;
};
Althoughonlyonemoduleisspecifiedinthisrecipe,oneofthepowerfulfeaturesoftheJAASsecuritydesignistousemultipleLoginModulesorlayersinordertoauthenticateusers.Ausermighthavetobeauthenticatedinseveralwaysbeforeshegainsaccesstowebcomponentsanddata(e.g.,firstheririsesarescanned,thenshemust
specifyausernameandpassword).
Theconfigurationfilespecifies:
ThefullyqualifiedclassnameoftheLoginModule(s).
A"Flag"value,whichisjustaconstantexpressionsuchas"required"or"requisite."Theexampleuses"requisite."Table15-1describesthedifferentFlagvalues.
Oneormore"options"(Example15-11doesnotidentifyanyoptions).Theoptionsrepresentaspace-separatedlistofname/valuepairs,suchasdebug="true"(youcanuseanyname/valuepairingyouwant).TheoptionsallowtheconfigurationfiletopasspropertiesandvaluestotheunderlyingLoginModule.
Table15-1.FlagvaluesforJAASconfigurationfiles
Flagname Description
RequiredTheLoginModuleisrequiredtosucceed,andoverallauthenticationfailsifaLoginModulemarked"required"fails.However,ifafailureoccurs,authenticationstillcontinuesdowntheLoginModulelist.
RequisiteTheLoginModuleisrequiredtosucceed,andruntimecontrolreturnstotheapplication(ratherthancontinuingwithanyotherlistedLoginModules)ifauthenticationfailureoccurs.
Sufficient
IftheLoginModulesucceeds,controlreturnstotheapplicationanddoesnotcontinuewithanyotherlistedLoginModules.Ifanauthenticationfailureoccurs,authenticationcontinueswithanyotherLoginModule.Inotherwords,thefailureofthisLoginModuledoesnotautomaticallyleadtothefailureofoverallauthentication,asin"required"or"requisite."
OptionalSuccessisnotrequiredwiththisLoginModule.Ifauthenticationsuccessorfailureoccurs,authenticationcontinueswithanyotherlistedLoginModules.
Thebasicstructureoftheconfigurationfilelookslikethis:
ApplicationName{
ModuleNameFlagOptions;
ModuleNameFlagOptions;
ModuleNameFlagOptions;
};
AnotherApplication{
ModuleNameFlagOptions;
ModuleNameFlagOptions;
};
Again,youdonothavetousemultipleLoginModules.
SeethisJavadocpageformoredetailsonconfiguration:http://java.sun.com/j2se/1.4.1/docs/api/javax/security/auth/login/Configuration.html.
HowdoestheJAASimplementationfindtheconfigurationfile?Thedirectory${java.home}/jre/lib/securitycontainsafilenamedjava.security.Thisisa"properties"or"policy"fileinJavasecurityparlanceatextfilecontainingname/valuepairs.ThefollowinglineoftextprovidesthelocationoftheJAASconfigurationfilefortheauthenticationservletofExample15-11:
login.config.url.1=file:h:/home/.java.login.config
IfyouhaveotherJAASconfigurationfilesthatyouwanttocombinewiththisone,usesyntaxsimilartologin.config.url.2=file:h:/home/.my.config(notetheincrementednumber2),placedwithinthejava.securityfile.
Youcanuseanyfilenamingconvention;theconfigurationfilenamedoesnothavetobeginwithaperiod.
AsingleJAASconfigurationfilecanspecifytheLoginModule(s)formultipleapplicationnames.Recipe15.8showsaservletthatusestheLoginModuledescribedinRecipe15.5.
SeeAlso
SunMicrosystems'JAASdeveloper'sguide:http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASLMDevGuide.htmlalistofJAAStutorialsandsampleprograms:http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.htmltheJavadocrelatingtoJAASconfigurationfiles:http://java.sun.com/j2se/1.4.1/docs/api/javax/security/auth/login/Configuration.htmlRecipe15.8onusingJAASwithaservlet;Recipe15.9onusingJAASwithaJSP.
Recipe15.8UsingJAASinaServlet
Problem
YouwanttoauthenticateservletclientswithJAAS.
Solution
CreateaJavaBeanthatwrapsthefunctionalityoftheJAASAPIclassesthatyouhaveincludedinyourwebapplication.
Discussion
UsingJAASinaservletrequiresthatyouhaveaLoginModuleinstalledinyourwebapplication,eitherinWEB-INF/classesorstoredinaJARfileinWEB-INF/lib.
Example15-12showsaservletnamedLoginServletthatimplementsJAASauthentication.ThisservletusestheCallbackHandlerdescribedinRecipe15.5.ThisCallbackHandlermustalsobeplacedinWEB-INF/classesorincludedinaJARstoredinWEB-INF/lib.Abrowserrequestforthisservletlookslike:
http://localhost:8080/home/servlet/com.jspservletcookbookLoginServlet?userName=Bruce%20W%20Perry&password=bwp1968
UseaPOSTrequestfromanHTMLforminconjunctionwithSSL(Recipe15.2)ifyouwanttousethemuchmoresecurestrategyofkeepingusernamesandpasswordsoutofvisibleURLs.
Example15-12.Aservletforauthenticatingandlogginginclients
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjavax.security.auth.login.LoginContext;
importjavax.security.auth.login.LoginException;
importjavax.security.auth.callback.CallbackHandler;
publicclassLoginServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//TheCallbackHandlergetstheusernameandpasswordfrom
//requestparametersintheURL;therefore,theServletRequestis
//passedtotheCallbackHandlerconstructor
WebCallbackHandlerwebcallback=newWebCallbackHandler(request);
LoginContextlcontext=null;
booleanloginSuccess=true;
try{
lcontext=newLoginContext("WebLogin",webcallback);
//thismethodthrowsaLoginException
//ifauthenticationisunsuccessful
lcontext.login();
}catch(LoginExceptionlge){
loginSuccess=false;
}
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Thanksforloggingin</title>"+
"</head><body>");
out.println("<h2>Yourloggedinstatus</h2>");
out.println(""+(loginSuccess?"Loggedin":
"FailedLogin"));
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
doGet(request,response);
}//doPost
}//LoginServlet
Thisservlet:
1. CreatesaWebCallbackHandler(Example15-10)andpassestheServletRequestintotheconstructor(fromwherethe
CallbackHandlergetstheclient'snameandpassword).
CreatesaLoginContextobjectwithtwoconstructorparameters:thenameoftheloginapplication(fromourconfigurationfileinRecipe15.6,"WebLogin")andtheWebCallbackHandlerobject.
CallstheLoginContext'slogin()method,whichbeneaththesurfacecallstheDataSourceLoginModule'slogin()method(fromExample15-9),inordertoperformauthentication.
Figure15-7showsthewebbrowseroutputwhenanattemptedloginusingthisservletsucceeds.
Figure15-7.TheLoginServletsignalssuccess
SeeAlso
Recipe15.6oncreatingaJAASLoginModule;Recipe15.7oncreatingtheJAASconfigurationfile;Chapter21onaccessingdatabaseswithservlets;SunMicrosystems'JAASdeveloper'sguide:http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASLMDevGuide.htmlalistofJAAStutorialsandsampleprograms:http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.htmltheJavadocrelatingtoJAASconfigurationfiles:http://java.sun.com/j2se/1.4.1/docs/api/javax/security/auth/login/Configuration.html
Recipe15.9onusingJAASwithaJSP.
Recipe15.9UsingJAASinaJSP
Problem
YouwanttouseaJSPandJAAStoauthenticateclients.
Solution
CreateaJavaBeanthatwrapsthefunctionalityoftheJAASAPIclassesthatyouhaveincludedinyourwebapplication.
Discussion
Recipe15.5-Recipe15.7covertheJAASbasics,sothisrecipefocusesonadaptingaJSPtotheJAASsecurityAPI.
TheJSPinthisrecipeusesaJavaBeantoperformthelogin.
TheJavaBeaninExample15-13hastwoproperties(intheformofinstancevariables):aServletRequestandabooleanvalueindicatingwhetherthenameandpasswordhavepassedthelogintest.ThebeanpassestheServletRequesttotheWebCallbackHandlerconstructor;theWebCallbackHandlerultimatelyextractstheusernameandpasswordfromrequestparameters.
Example15-13.AJavaBeanusestheJAASAPItoperformauthentication
packagecom.jspservletcookbook;
importjavax.servlet.ServletRequest;
importjavax.security.auth.login.LoginContext;
importjavax.security.auth.login.LoginException;
publicclassLoginBean{
//privatebeaninstancevariablesorproperties
privateServletRequestreq;
booleanloginSuccess;
publicLoginBean(){}//bean'sno-argsconstructor
publicbooleangetLoginSuccess()throwsLoginException{
//theServletRequestpropertyhastobesetbeforethis
//methodiscalled,becausethat'swherewegetthe
//usernameandpasswordfrom
if(req==null)
thrownewIllegalStateException(
"TheServletRequestcannotbenullingetLogin()");
WebCallbackHandlerwebcallback=newWebCallbackHandler(req);
try{
LoginContextlcontext=newLoginContext(
"WebLogin",webcallback);
//CalltheLoginContext'slogin()method;ifitdoesn't
//throwanexception,themethodreturnstrue
lcontext.login();
returntrue;
}catch(LoginExceptionlge){
//loginfailedbecausetheLoginContext.login()method
//threwaLoginException
returnfalse;
}
}//getLoginSuccess
publicvoidsetReq(ServletRequestrequest){
if(request==null)
thrownewIllegalArgumentException(
"ServletRequestargumentwasnullin:"+
getClass().getName());
this.req=request;
}//setReq
}//LoginBean
ThebeandependsonitsServletRequestpropertybeingsetproperlybeforethegetLoginSuccess()methodiscalled.ThismethodperformstheloginbyusingthefamiliarLoginContextclassanditslogin()method(thatis,familiarifyoureadRecipe15.5!).
TheJavaobjectusingthebeanknowsthattheloginsucceededorfailedbasedonthebooleanreturnvalueofthegetLoginSuccess()method.TheobjectusingthebeaninthiscaseisaservletinstanceoriginatingfromtheJSPinExample15-14.
TheJSPincludesthejsp:useBeanstandardactiontocreateaninstanceoftheLoginBean(inavariablenamedjaasBean).ThenthecodeusesJSTLtagsto:
1. Setthebean'sServletRequestproperty(namedreq)tothecurrentrequest(usingc:set).
FindoutwhethertheloginsucceededbyusingtheELsyntaxtocallthebean'sgetLoginSuccess()method.
ThisrecipecombinesmanyJava-relatedtechnologies.SeeChapter23foradescriptionoftheJSTLanditsassociatedELsyntax.
Example15-14.AJSPthatlogsinusersusingtheJAASAPIandaJavaBean
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>AuthenticatingJSP</title></head>
<body>
<h2>Hereisyourloginstatus...</h2>
<jsp:useBeanid="jaasBean"class="com.jspservletcookbook.LoginBean"/>
<%--Thebean's'req'propertyissetusingthe'request'propertyoftheExpression
Language'spageContextimplicitobject--%>
<c:settarget="${jaasBean}"value="${pageContext.request}"
property="req"/>
<c:choose>
<c:whentest="${jaasBean.loginSuccess}">
Loggedinsuccessfully.
</c:when>
<c:otherwise>
Loginfailed.
</c:otherwise>
</c:choose>
</body>
</html>
TheLoginBeanhasagetLoginSuccess()methodthatreturnsfalseiftheloginfails,andtrueifitsucceeds.WiththeEL,youcancallanyofabean'saccessormethodswiththeterminology:
beanname.beanpropertyname
Thebeanpropertynamepartrepresentstheactualpropertyname,notthenameofthemethod,eventhoughtheendresultofusingthissyntaxisthattheaccessormethodassociatedwiththatpropertygetscalled.Therefore,Example15-14getsthereturnvalueofthegetLoginSuccess()methodbyusing:
${jaasBean.loginSuccess}
Ifthisexpressionreturnstrue,theJSPdisplaysthetext"Loggedinsuccessfully."Otherwise,itshows"Loginfailed."
Figure15-8showstheJSP'sbrowserdisplaywhenaloginfails.
Figure15-8.AJSPsignalsaloginfailure
SeeAlso
Recipe15.6oncreatingaJAASLoginModule;Recipe15.7oncreatingtheJAASconfigurationfile;Recipe15.8onusingJAASwithaservlet;Chapter23ontheJSTL;SunMicrosystems'JAASdeveloper'sguide:http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASLMDevGuide.htmlalistofJAAStutorialsandsampleprograms:http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.htmltheJavadocrelatingtoJAASconfigurationfiles:http://java.sun.com/j2se/1.4.1/docs/api/javax/security/auth/login/Configuration.html
Chapter16.Binding,Accessing,andRemovingAttributesinWebApplications
Introduction
Recipe16.1.SettingServletContextAttributesinServlets
Recipe16.2.SettingServletContextAttributesinJSPs
Recipe16.3.AccessingorRemovingServletContextAttributesinServlets
Recipe16.4.AccessingorRemovingServletContextAttributesinJSPs
Recipe16.5.SettingSessionAttributesinServlets
Recipe16.6.SettingSessionAttributesinJSPs
Recipe16.7.AccessingorRemovingSessionAttributesinServlets
Recipe16.8.AccessingorRemovingSessionAttributesinJSPs
Recipe16.9.SettingRequestAttributesinServlets
Recipe16.10.SettingRequestAttributesinJSPs
Recipe16.11.AccessingorRemovingRequestAttributesinServlets
Recipe16.12.AccessingorRemovingRequestAttributesinJSPs
Introduction
AnattributeisaJavaobjectthatservletcodecanbind,orstore,inacertainscope,suchasaServletContext,asession,orarequest.Theobjectcantemporarilystoreandshareasmallpieceofdatainawaythatisnototherwiseavailabletoservletdevelopers.Then,whentheapplicationnolongerhasusefortheobject,yourcodecanremove,orunbindit,andthewebcontainermakestheobjectavailableforgarbagecollection.
Thischapterdescribeshowtoworkwithattributesinallthreescopes:ServletContext,session,andrequest.IfyouneedtomakeanobjectavailabletoalloftheservletsandJSPsinacontext,thenyoucanbindtheobjecttoaServletContext.Iftheapplicationcallsforanobjectsuchasa"shoppingcart"tobeboundtoasession(seeChapter11),youcansettheobjectasasessionattribute.Finally,iftheapplicationrequirestwoservletsthatcommunicateviaaRequestDispatchertoshareanobject,thentheservletscanuseanobjectattributeboundtoarequestscope.
Sincesessionsandrequestsareassociatedwithnumeroususersinabusywebapplication,developershavetopayattentiontothesizeandresourceuseofanyobjectsthatareboundasattributestorequestsorsessions.
Recipe16.1SettingServletContextAttributesinServlets
Problem
Youwanttomakeanobjectavailabletoallservletsinacontextorwebapplication.
Solution
BindanobjecttotheServletContextusingthejavax.servlet.ServletContext.setAttribute()method.
Discussion
AServletContextattributeisavailabletoallservletsandJSPsinacontextorwebapplication.HerearethestepstobindanobjecttoaServletContext:
1. CreatetheJavaclassthatyouwanttobindtoaServletContext.
PlacetheclassintheWEB-INF/classesdirectory,includingthenecessarypackage-relateddirectories.YoucanalsostoretheclassinaJARfileinWEB-INF/lib.
CreateaservletthatbindstheobjecttotheServletContextusingthejavax.servlet.ServletContext.setAttribute()method.
AccesstheobjectusingServletContext.getAttribute()in
(other)servletswheneveritisneeded.
I'llfirstshowtheobjectthatthisrecipebindstotheServletContext.TherecipethendemonstratesaservletthatstorestheobjectattributeintheServletContext.Example16-1showsasimpleobjectwrappedaroundajava.util.Maptype.UsetheMaptostoreacharacteristicofeachrequestmadetothewebapplication.Inthisexample,eachMapkeyistheIPaddressoftheclientmakingtherequest.EachMapvalueisthedateitrequestedtheservlet.
Example16-1.TheobjectthataservletbindstotheServletContext
packagecom.jspservletcookbook;
importjava.util.Collections;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Map;
importjava.util.Set;
publicclassContextObject{
privateMapmap;
publicContextObject(){
map=Collections.synchronizedMap(newHashMap());
}
publicvoidput(Objectkey,Objectvalue){
if(key==null||value==null)
thrownewIllegalArgumentException(
"InvalidparameterspassedtoContextObject.put");
map.put(key,value);
}
publicStringgetValues(){
StringBufferbuf=newStringBuffer("");
Setset=map.keySet();
//youhavetoexplicitlysynchronizewhenanIteratorisused
synchronized(map){
Iteratori=set.iterator();
while(i.hasNext())
buf.append((String)i.next()+"<br>");
}//synchronized
returnbuf.toString();
}
publicStringtoString(){
returngetClass().getName()+"["+map+"]";
}//toString
}
TheContextObjectclasshasmethodstoaddkeysandvaluestotheMap(put(Objectkey,Objectvalue))aswellastooutputtheMap'scurrentkeyvalues(getValues()).TheMapissynchronized,whichisessentiallythread-safe;itiscreatedintheContextObject'sconstructorinthefollowingmanner:
map=Collections.synchronizedMap(newHashMap());
WhenyougenerateaMapusingthestaticjava.util.Collections.synchronizedMap()method,onlyonethreadatatimecancalltheMap'smethods.ThisisimportantwithServletContextattributesthatmaybeaccessedbyseveralservletsand/ormultiplethreadsatthesametime.
Example16-2showstheskeletonoftheContextBinderservletthatbindsaninstanceoftheContextObjectclassinExample16-1totheServletContext.
Example16-2.AservletbindsanobjecttotheServletContext
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassContextBinderextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throws
ServletException,java.io.IOException{
//bindanobjecttotheServletContext
getServletContext().setAttribute(
"com.jspservletcookbook.ContextObject",newContextObject());
//displaysomeHTML
...
}//enddoGet
}
TheservletmethodgetServletContext()returnsa
javax.servlet.ServletContextinstance.Youthencallthatinstance'ssetAttribute()methodwiththeStringattributenameandtheboundobjectasparameters.Asaconvention,youshouldconsidernamingattributesaftertheirfullyqualifiedclassnameinthiscase,"com.jspservletcookbook.ContextObject."
SeeAlso
Recipe16.2onsettingServletContextattributesinJSPs;Recipe16.3onaccessingorremovingaServletContextattribute;Recipe16.5-Recipe16.8onhandlingsessionattributesinservletsandJSPs;Recipe16.9-Recipe16.12onhandlingrequestattributesinservletsandJSPs;Recipe14.5onusingaServletContexteventlistener;theJavadocforjavax.servlet.ServletContextAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletContextAttributeListener.html
Recipe16.2SettingServletContextAttributesinJSPs
Problem
YouwanttostoreanobjectattributeintheServletContextusingaJSP.
Solution
UsetheJSTLc:settagtobindanobjecttoapplicationscope.TheJSTLusestheapplicationimplicitobjecttorepresenttheServletContext,whichisalsothescopeusedfortheobjectattributesdiscussedinthepreviousrecipe.
Discussion
JSPdeveloperscanusetheJSTLcoretagsandthejsp:useBeanstandardactiontoimplementthesamefunctionalityastheservletinRecipe16.1.Liketheprograminthatrecipe,theupcomingJSPstoresintheServletContextanobjectattributethatcontainsajava.util.Maptype.TheMapstoreskey/valuepairsthatareaccessedbyotherservletsorJSPsinthesamecontext.
HerearethestepstobindanattributetotheServletContextusingaJSP:
1. CreatetheJavaclassthatyouwillinstantiateandbindtotheServletContext.
PlacetheJavaclassintheWEB-INF/classesdirectory,includinganypackage-relateddirectories(iftheclassisnamedcom.jspservletcookbook.ContextObjectthenplacetheclassinWEB-INF/classes/com/jspservletcookbook),orinWEB-INF/libiftheclassisstoredinaJARfile.
CreatetheJSPthatwillbindtheobjectattributetotheServletContext.StoretheJSPinthewebapplication'stop-leveldirectory.
IfthewebcontainerdoesnotalreadyprovidetheJSTL-relatedcomponents,includetheminWEB-INF/lib(seeChapter23)sothattheJSPcanusethesetaglibraries.
FirstIshowtheobjectattributethattheJSPbindstotheServletContext.Example16-3isthesameJavaclassasExample16-1,exceptforthegetMap()method,whichreturnstheMaptypethatthisobjectusestostoreinformation.IaddedthismethodtomaketheMapavailabletothec:setcoretag(seeExample16-4).BecausethetwocodesamplesareexactlythesameexceptforthegetMap()method,Example16-3hasbeenabbreviatedtoshowjustthecreationofthesynchronizedmapanditsgettermethod(seeExample16-1fortheotherpartsoftheclass).
Example16-3.TheobjectattributeboundtotheServletContextbyaJSP
packagecom.jspservletcookbook;
importjava.util.Collections;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Map;
importjava.util.Set;
publicclassContextObject{
privateMapmap;
publicContextObject(){
map=Collections.synchronizedMap(newHashMap());
}
publicMapgetMap(){
returnmap;
}
//seeExample16-1fortheotherpartsoftheclass
}
Example16-4doestheworkofcreatinganinstanceoftheobjectattributeandthenbindingtheattributetotheServletContext.ThecodecreatestheContextObjinstance(whichisstoredintheServletContext)withthejsp:useBeanstandardaction.Thenthec:setJSTLcoretagstoresthisobjectinapplicationscope,whichisanaliasfortheServletContext.TheContextObjclassstoresinformationwithaMaptypethatitcontains.ThiscodeinExample16-4storesdataintheServletContextattribute:
<c:settarget=
"${applicationScope[\"com.jspservletcookbook.ContextObject\"].map}"
value="${date}"property="${pageContext.request.remoteAddr}"/>
ThevalueofthetargetattributehastheeffectofcallinggetMap()ontheContextObjobject.Thecodethencreatesanewkey-valuepairintheMap,consistingoftheremoteIPaddressoftheclientmakingtherequest(thekey)andthecurrentdate(thevalue).Ichosethisinformationatrandomtodemonstratehowtostorepiecesofdataina
ServletContextattributeusingtheJSTLandJSPs.Yourowncodemaystoredataofpracticalvaluetoyourapplicationsuchasacustomer'suniqueIDandtheitemthatheispurchasing.
Example16-4.ThecontextBind.jspfile
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>ContextbindingJSP</title></head>
<body>
<h2>HereistheboundContextObject</h2>
//createaninstanceofContextObject;storeitasaPagescopedattribute
<jsp:useBeanid="contextObj"class=
"com.jspservletcookbook.ContextObject"/>
//createaninstanceofDate;storeitasaPagescopedattribute
<jsp:useBeanid="date"class="java.util.Date"/>
//bindtheobjecttotheServletContextrepresentedbythe
//'application'implicitobject
<c:setvar=
"com.jspservletcookbook.ContextObject"value="${contextObj}"scope=
"application"/>
//createanewkey/valuepairintheboundobject'sMap
<c:settarget=
"${applicationScope[\"com.jspservletcookbook.ContextObject\"].map}"
value="${date}"property="${pageContext.request.remoteAddr}"/>
</body>
</html>
Afterlookingatthiscode,youmaywonderwhytheContextObjectvariableiseffectivelynamedtwice,oncebyjsp:useBeanwhenit
createstheobject(givingtheobjectanidornamecontextObj)andagainbyc:setwhenitbindstheobjecttotheServletContext(andcreatingthenamecom.jspservletcookbook.ContextObject).
Byconvention,youshouldnametheattributeafteritsfullyqualifiedclassname.However,youcannotusethisformatwithjsp:useBean,becausethisactioncreatesaJavavariableintheunderlyingservlet.TheJavavariableisnamedcontextObj.
TheJSPcontainercreatesaservletbehindthescenestoimplementeachJSPpage.
Youcannotincludeperiod(.)characterswhennamingJavavariables,sothecoderenamestheobjectinc:set'svarattributewhentheobjectisboundtotheServletContext.
SeeAlso
Chapter23onusingtheJSTL;Recipe16.1onsettingServletContextattributesinservlets;Recipe16.4onaccessingorremovingaServletContextattributeinaJSP;Recipe16.5-Recipe16.8onhandlingsessionattributesinservletsandJSPs;Recipe16.9-Recipe16.12onhandlingrequestattributesinservletsandJSPs;Recipe14.5onusingaServletContexteventlistener;theJavadocforjavax.servlet.ServletContextAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletContextAttributeListener.html
Recipe16.3AccessingorRemovingServletContextAttributesinServlets
Problem
YouwanttoaccessaServletContextattributetoworkwithitincode,orcompletelyremoveit.
Solution
UsetheServletContext.getAttribute(StringattributeName)methodtoaccesstheattribute.UsetheServletContext.removeAttribute(StringattributeName)
methodtoremovetheattributefromtheServletContext.
Discussion
ThecodeinExample16-5getstheServletContextattributeandstoresitinalocalvariable.Thenthecodeaddsanewkey/valuetotheattribute(whichcontainsajava.util.Maptypeforstoringthekeysandvalues).Later,theservletprintsoutalistoftheattribute'skeys,whichareIPaddressesassociatedwithrequeststotheservlet.
Example16-5.AccessingaServletContextattributeinaservlet
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassContextAccessorextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//getaServletContextattribute
ContextObjectcontextObj=(ContextObject)
getServletContext().getAttribute(
"com.jspservletcookbook.ContextObject");
if(contextObj!=null)
contextObj.put(request.getRemoteAddr(),""+
newjava.util.Date());
//displaythecontextattributevalues
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>ContextAttribute</title></head><body>");
if(contextObj!=null){
out.println("<h2>ServletContextAttributeValues</h2>");
out.println(contextObj.getValues());
}else{
out.println("<h2>ServletContextAttributeisNull</h2>");
}
out.println("</body></html>");
}//enddoGet
}
Example16-1inRecipe16.1showstheContextObjectsourcecode.Here,theContextObjectput()methodpassesitskeyandvalueparameterstotheMapmethodofthesamename,exceptthattheContextObjectput()methoddoesnotallownullvaluesforeither
itskeysorvalues.
Ifyouwanttoremovethesameattributethatwasboundbythisrecipe,calltheServletContext.removeAttribute()methodwiththeattributenameasaparameter:
getServletContext().removeAttribute(
"com.jspservletcookbook.ContextObject");
Aftertheattributeremovalcodeexecutes,anyfurthercallstoServletContext.getAttribute()usingthesameattributenamewillreturnnull.
SeeAlso
Recipe16.1andRecipe16.2onsettingServletContextattributesinservletsandJSPs;Recipe16.5-Recipe16.8onhandlingsessionattributesinservletsandJSPs;Recipe16.9-Recipe16.12onhandlingrequestattributesinservletsandJSPs;Recipe14.5onusingaServletContexteventlistener;theJavadocforjavax.servlet.ServletContextAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletContextAttributeListener.html
Recipe16.4AccessingorRemovingServletContextAttributesinJSPs
Problem
YouwanttoaccessorremoveaServletContextattributeinaJSP.
Solution
Usethec:outJSTLcoretagtodisplaythevalueofanattributeandthec:removetagtoremovetheattributefromtheServletContext.
Discussion
BynowyouareprobablyfamiliarwiththeobjectattributethatthepreviousrecipesstoredintheServletContextunderthenamecom.jspservletcookbook.ContextObject.Ifyouarenot,Recipe16.1andRecipe16.2showthesourcecodeforthisclassandhowitisboundasanattributetoaservletandaJSP.ThisrecipeshowstheJSTLtagsthatyoucanuseinJSPcodetoaccessthisattributeandoptionallyremoveorunbindit.
Example16-6includesthetaglibdirectivethatisrequiredforusingJSTL1.0tagsinaJSP.Thec:outtagthenaccessestheServletContextattributeinthetag'svalueattribute.ThetaggetsthevalueoftheServletContextattributebyusingtheapplicationScopeJSTLimplicitobject,whichisajava.util.Maptype.
Example16-6.AccessinganapplicationattributeinaJSP
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
//HTMLorotherpresentationcodehere...
<c:outvalue=
"${applicationScope[\"com.jspservletcookbook.ContextObject\"].values}"
escapeXml="false"/>
AnimplicitobjectisanobjectthattheJSTLautomaticallymakesavailabletothedeveloper.YouusethetermapplicationScopewithin${...}characters,andthistermevaluatestoajava.util.MapofanyobjectattributesthatareboundtotheServletContext.
Thecode:
${applicationScope[\"com.jspservletcookbook.ContextObject\"].values}
usesELsyntaxtoaccesstheServletContextattributenamedcom.jspservletcookbook.ContextObjectandgetitsvaluesproperty,whicheffectivelycallsthegetValues()methodontheContextObjectobject.ThismethoddisplaysallthekeysoftheMapcontainedbyContextObject,separatedbyanHTMLlinebreak(<br>).TheattributeescapeXml="false"preventsthe<and>charactersin<br>frombeingescaped(andbeingreplacedby<and>,respectively),whichwouldpreventitsproperdisplayinawebbrowser.
IfIwantedtomaketheContextObjectmoreuniversal,IcouldincludeaJavaBeanpropertyallowingtheuseroftheclasstosetthelineseparator,sothattheoutputofthegetValues()methodcouldbeusedindifferentcontexts,notjustHTML.
Figure16-1showstheresultofaccessingaJSPthatusesthiscodeinabrowser.
Figure16-1.AccessingaServletContextboundattributeinaJSP
ToremovetheattributefromtheServletContext,usethec:removeJSTLtag.Thistagremovesthenamedvariablefromthespecifiedscope:
<c:removevar=
"com.jspservletcookbook.ContextObject"scope="application"/>
applicationisanaliasfortheServletContext.AfteraJSPthatcontainsthistagisexecuted,anyfurtherattemptstoaccessaServletContextattributeofthesamenamewillreturnnull.
SeeAlso
Chapter23onusingtheJSTL;Recipe16.1andRecipe16.2onsettingServletContextattributesinservletsandJSPs;Recipe16.3onaccessingorremovingServletContextattributesinservlets;Recipe
16.5-Recipe16.8onhandlingsessionattributesinservletsandJSPs;Recipe16.9-Recipe16.12onhandlingrequestattributesinservletsandJSPs;Recipe14.5onusingaServletContexteventlistener;theJavadocforjavax.servlet.ServletContextAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletContextAttributeListener.html
Recipe16.5SettingSessionAttributesinServlets
Problem
Youwanttostoreanobjectattributeinasession.
Solution
Usethejavax.servlet.http.HttpSessionclass'ssetAttribute()method.
Discussion
ThemechanismforplacingobjectattributesinsessionsisverysimilartostoringobjectsintheServletContext,whichRecipe16.1described.Thedifferenceliesinthescopeoftheobjects;inotherwords,whichusersandhowmanyconcurrentuserscanaccesstheboundobjects.
Asessionrepresentstheinteractionofauserwithawebsite.Thesequenceofwebpagesorcomponentsthatasingleuserrequestsfromawebsiterepresentsasinglesession(detailedinChapter11).Therefore,whenyoustoreanobjectinstanceinasessionattribute,everyuserwhoparticipatesinsessionsinteractswithhisowninstanceofthatobjectattribute.WithServletContextattributes,however,alloftheapplication'susersinteractwiththesameattributeinstance,sinceeachwebapplicationhasonlyoneServletContextandeachcontextisassociatedwithoneattributeinstance.
AdistributedwebapplicationhasoneServletContextinstanceperJavavirtual
machine(JVM).InsteadofusingtheServletContexttostoreinformationgloballyfortheapplication,theServletContextJavadocmakesbriefmentionofusingadatabaseinstead,toensurethatservletsinadistributedapplicationareaccessingthesamedata.SeetheServletContextJavadocat:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletContext.html.
Ashoppingcartstoringauser'sitemchoicesisanexampleofanobjectthatwebdeveloperstypicallystoreasasessionattribute.Example16-7showsafragmentofservletcodeforstoringanobjectinasession.
Example16-7.Storinganobjectattributeinasession
<!--thiscodeappearsintheservlet'sdoGetordoPostmethod,whicheverisappropriate-
->
//Createasessionifonedoesnotexistyet
HttpSessionsession=request.getSession();
//bindanobjectattributeinthesession
if(session!=null)
session.setAttribute(
"com.jspservletcookbook.ContextObject",newContextObject());
Gainaccesstoasessioninaservletbyusingthejavax.servlet.http.HttpServletRequestobject'sgetSession()method.ThencallHttpSession.setAttribute(),passinginthenameoftheattributeandaninstanceoftheobjectattribute.ThecodeinExample16-7usesthesameContextObjectthatExample16-1showed(Recipe16.1).TheContextObjectusesasynchronizedjava.util.Maptypetohandlemultiplethreadsthatmightbeusingtheattributeconcurrently.
Payattentiontothepossibilityofmultiplethreadsaccessingasessionobject
attribute.Accordingtotheservletspecificationv2.4(ChapterSRV.7.7.1),"Multipleservletsexecutingrequestthreadsmayhaveactiveaccesstoasinglesessionobjectatthesametime.Thedeveloperhastheresponsibilityforsynchronizingaccesstosessionresourcesasappropriate."
SeeAlso
Recipe16.1-Recipe16.4onhandlingServletContextattributesinservletsandJSPs;Recipe16.7onaccessingorremovingsessionattributesinservlets;Recipe16.6andRecipe16.8onhandlingsessionattributesinJSPs;Recipe16.9-Recipe16.12onhandlingrequestattributesinservletsandJSPs;Recipe14.6onusingasessioneventlistener;theJavadocforjavax.servlet.http.HttpSessionAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/HttpSessionAttributeListener.html
Recipe16.6SettingSessionAttributesinJSPs
Problem
YouwanttobindanobjecttoasessioninaJSP.
Solution
Usethejsp:useBeanandc:settagstocreateaninstanceofanobjectandassignitasanattributetothesession.
Discussion
TheJSTLcoretagsandthejsp:useBeanstandardactioncanbeusedtomanagesessionattributesinJSPs.Example16-8bindsanobjectattributetoasession,displaysavaluefromtheobject,andthenshowsthesessionIDoftheclientwhorequestedtheJSP.TheboundobjectistheContextObjectthatIhaveusedthroughoutthischapterasthestoredattribute.Itcontainsajava.util.MaptypeforstoringtheIPaddressesofuserswhorequesttheJSP(seeExample16-1andtheaccompanyingdescriptionofthecode).
Example16-8.SettingasessionattributeinaJSP
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>ContextbindingJSP</title></head>
<body>
<h2>HerearethevaluesfromtheboundContextObject</h2>
<%--CreateinstancesoftheContextObjectandDateclasses--%>
<jsp:useBeanid="contextObj"class=
"com.jspservletcookbook.ContextObject"/>
<jsp:useBeanid="date"class="java.util.Date"/>
<%--Bindtheobjectattributetothesessionscope--%>
<c:setvar=
"com.jspservletcookbook.ContextObject"value="${contextObj}"scope=
"session"/>
<%--Putavalueintheobject,thendisplaythevalue--%>
<c:settarget=
"${sessionScope[\"com.jspservletcookbook.ContextObject\"].map}"value=
"${date}"property="${pageContext.request.remoteAddr}"/>
<c:outvalue="${sessionScope[\"com.jspservletcookbook.ContextObject\"].
values}"escapeXml="false"/>
<h2>HereisthesessionID</h2>
<c:outvalue="${pageContext.session.id}"/>
</body>
</html>
ThiscodefromExample16-8bindstheobjecttothesession:
<c:setvar=
"com.jspservletcookbook.ContextObject"value="${contextObj}"scope=
"session"/>
TheonlydifferencebetweenExample16-8andtheJSPofRecipe16.2,whichbindstheobjecttotheServletContext,isthevalueofthescopeattributeinthec:settag(sessioninthiscase).Insimilarfashion,thec:settagsetsavalueinthesessionattributebyreferringtothesessionScopeimplicitvariable:
<c:settarget=
"${sessionScope[\"com.jspservletcookbook.ContextObject\"].map}"value=
"${date}"property="${pageContext.request.remoteAddr}"/>
TheELmechanismautomaticallymakesavailablethesessionScopeimplicitvariable,whichrepresentsajava.util.Maptypethatstoresanyobjectvariablesinsessionscope.
Ifyouhaveanattributenamethatdoesnotincludeperiodcharactersinit,youcanprovidetheattributenamewithoutanyfurthercontext,andtheELwillsearchthepage,request,session,andapplicationscopesforanattributeofthatname.Forexample,thefollowingELsyntaxreturnsasessionobjectattributenamedcontextObjwithoutusinganimplicitvariable(ornullifthatsessionattributedoesnotexist)tofurtherqualifythename:
${contextObj}
SeeAlso
Chapter23onusingtheJSTL;Recipe16.1-Recipe16.4onhandlingServletContextattributesinservletsandJSPs;Recipe16.7onaccessingorremovingsessionattributesinservlets;Recipe16.8onaccessingorremovingsessionattributesinJSPs;Recipe16.9-Recipe16.12onhandlingrequestattributesinservletsandJSPs;Recipe14.6onusingasessioneventlistener;theJavadocforjavax.servlet.http.HttpSessionAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/HttpSessionAttributeListener.html
Recipe16.7AccessingorRemovingSessionAttributesinServlets
Problem
Youwanttoaccessorremoveasessionattributeinaservlet.
Solution
Usethejavax.servlet.http.HttpSession.getAttribute(String
attributeName)methodtoaccesstheattribute.UsetheremoveAttribute(StringattributeName)methodtoremovetheattributefromthesession.
Discussion
Toaccessasessionattribute,youmustfirstbindtheattributetoasession,asinRecipe16.5.Theobjectattributeisnowavailabletotheuserassociatedwiththatsession.Example16-9accessesanattributenamedcom.jspservletcookbook.ContextObject.Theexamplejustshowsthecoderelatingtoaccessinganattributefromthesession.Example16-5inRecipe16.3showstheentireservletanddoGet()methodforaccessinganobjectattribute.
TheHttpSession.getAttribute()methodreturnsanObjecttype,sothereturnvaluehastobecasttotheappropriatetypebeforecallinganymethodsonit.
Example16-9.Gainingaccesstothesessionattributeinaservlet
packagecom.jspservletcookbook;
...
<!--thiscodeappearsintheservlet'sdoGetordoPostmethod,whicheverisappropriate.
TheContextObjectclassisstoredinWEB-INF/classes/com/jspservletcookbook/-->
//Createasessionifonedoesnotexistyet
HttpSessionsession=request.getSession();
//Thislocalvariablewillholdtheobjectattribute
ContextObjectcontextObj=null;
//getaccesstoanobjectattributeinthesession
if(session!=null)
contextObj=(ContextObject)session.getAttribute(
"com.jspservletcookbook.ContextObject");
//ensurethecontextObjisnotnullbeforecallinganymethods
if(contextObj!=null)
out.println(contextObj.getValues());
<!--restofservletclassanddoGetordoPostmethodgoeshere-->
Youmusttakethesestepsbeforeaccessingasessionattribute:
1. Compiletheclassoftheobjectthatwillbestoredinthesession.
PlacethisclassinWEB-INF/classesorinWEB-INF/libifit'sstoredinaJARfile.
Makesureaservlet,JSP,orotherwebcomponentsetstheattributetothesessionwiththeHttpSession.setAttribute()method.
Removingthesessionattributefromaservlet
Toremoveanattribute,callHttpSession.removeAttribute()withthenameoftheattribute.Usethefollowingcodeinaservlettoremovetheattributethischapterhasbeenworkingwith:
HttpSessionsession=request.getSession();
<!--HttpSession.removeAttributewillhavenoeffectifanattributeofthatname
doesnotexist-->
if(session!=null)
session.removeAttribute("com.jspservletcookbook.ContextObject");
Nowtheattributeisnolongeravailableinthesessionassociatedwiththeuserthatrequestedtheservlet.Thesessionattributeisstillavailableinothersessionswhereitmaybestored(albeitintheformofadifferentinstance).Eachuserisassociatedwithaspecificsession,andeachsessioncancarryitsowninstanceoftheobjectattribute.
WhenyouremovetheattributefromtheServletContext,ontheotherhand,itisnolongeravailabletoanyusers,becausethereisonlyoneServletContextforeachnondistributedwebapplication.
SeeAlso
Recipe16.1-Recipe16.4onhandlingServletContextattributesinservletsandJSPs;Recipe16.5onsettingsessionattributesinservlets;
Recipe16.6onsettingsessionattributesinJSPs;Recipe16.8onaccessingorremovingsessionattributesinJSPs;Recipe16.9-Recipe16.12onhandlingrequestattributesinservletsandJSPs;Recipe14.6onusingasessioneventlistener;theJavadocforjavax.servlet.http.HttpSessionAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/HttpSessionAttributeListener.html
Recipe16.8AccessingorRemovingSessionAttributesinJSPs
Problem
YouwanttoaccessorremoveasessionattributeinaJSP.
Solution
Usethec:outJSTLcoretagtodisplaythevalueofanattributeandthec:removetagtoremovetheattributefromthesession.
Discussion
Herearethestepstoaccessorremoveasession-scopedvariablewiththeJSTLandaJSP:
1. MakesurethatyourwebapplicationisabletousetheJSTL(i.e.,youhavetheproperJARfilessuchasjstl.jarandstandard.jarinyourWEB-INF/libdirectory;seeChapter23forinstructions).
Includethetaglibdirective,whichmakestheJSTLcoretagsavailabletotheJSP(seetheupcomingcode).
Makesuretheobjectattributeisboundtothesessioninthefirstplace,eitherbythesameJSPthataccessestheattribute,orbyanotherwebcomponent(suchasaservlet).
Thecodeinthisrecipeshowshowtoreferenceasession-scoped
variable,asopposedtoaServletContextattribute(showninRecipe16.4).ThiscodeusesthesessionScopeimplicitobjectoftheEL,whichisanautomaticallyavailablevariableinELformatthatcontainsanysession-scopedobjectattributes.ThiscoderepresentsaportionofaJSPthatdisplaysthevaluescontainedinanattributenamedcom.jspservletcookbook.ContextObject.
Example16-4inRecipe16.2showsacompleteJSPthataccessesobjectattributes.Recipe16.2accessesaServletContextattributeinaJSP,ratherthanasession-scopedattribute.
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
//HTMLorotherpresentationcodehere...
<c:outvalue=
"${sessionScope[\"com.jspservletcookbook.ContextObject\"].values}
escapeXml="false"/>
TheescapeXml="false"partofthec:outtagtellsthetagtoleavecharactersthatarepartofthetag'soutputsuchas<and>unescaped(inotherwords,donotconvertthemtocharacterentitiessuchas<and>).
ThisJSPcoderemovesasession-scopedvariableusingthec:removecoretag:
<c:removevar=
"com.jspservletcookbook.ContextObject"scope="session"/>
TheobjectattributeisnolongeravailablefortheindividualsessionassociatedwiththeuserthatrequestedthisJSP.Inotherwords,thec:removetagdoesnotremoveallsessionattributesofthespecified
name,justthesessionattribute(s)associatedwithanyuserwhorequeststheJSPcontainingthec:removetag.
SeeAlso
Chapter23onusingtheJSTL;Recipe16.1-Recipe16.4onhandlingServletContextattributesinservletsandJSPs;Recipe16.5onsettingsessionattributesinservlets;Recipe16.6onsettingsessionattributesinJSPs;Recipe16.7onaccessingorremovingsessionattributesinservlets;Recipe16.9-Recipe16.12onhandlingrequestattributesinservletsandJSPs;Recipe14.6onusingasessioneventlistener;theJavadocforjavax.servlet.http.HttpSessionAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/HttpSessionAttributeListener.html
Recipe16.9SettingRequestAttributesinServlets
Problem
Youwanttouseaservlettostoreanattributeinarequest.
Solution
Usethejavax.servlet.ServletRequest.setAttribute()method.
Discussion
TheServletRequest.setAttribute()methodisoftenusedincodethatdynamicallyforwardsrequestsorincludescontentwithajavax.servlet.RequestDispatcher.
WebapplicationsthatuseRequestDispatcherstosharerequestsbetweenwebcomponentscancommunicatebetweenthesecomponentsusingrequestattributes.BoththerecipientoftheRequestDispatcher.forward()methodandtheincludedfileorpageinvolvedwiththeRequestDispatcher.include()methodhaveaccesstotheoriginalorenclosingrequest.Therefore,thesewebcomponentscanalsoaccessanyobjectattributesthatarestoredinthoserequests.
TheservletinExample16-10createsaninstanceofaContextObject,storessomeinformationintheobjectbycallingitsput()method,andthenplacestheobjectintheHttpServletRequestunderthename
"com.jspservletcookbook.ContextObject."TheservletthenusesaRequestDispatchertoforwardtherequest(includingtheattribute)andresponsetotheservletpath/displayAttr.Thewebcomponentmappedtothatservletpathnowhasaccesstothepreviouslycreatedrequestattribute.
Example16-10.Bindinganobjecttoarequest
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassRequestBinderextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//bindanobjecttotherequest
ContextObjectcontextObj=newContextObject();
contextObj.put(request.getRemoteAddr(),""+newjava.util.Date());
request.setAttribute(
"com.jspservletcookbook.ContextObject",contextObj);
//useRequestDispatchertoforwardrequesttoanotherservlet
//mappedtotheservletpath'/displayAttr'
RequestDispatcherdispatcher=request.getRequestDispatcher(
"/displayAttr");
dispatcher.forward(request,response);
}//doGet
}
Example16-11showstheservletthatreceivestheforwardedrequest.TheRequestDisplayservletismappedinweb.xmltothe/displayAttrservletpath.ThisservletgetstherequestattributefromtheHttpServletRequestobjectbycallinggetAttribute()withtheattributename:com.jspservletcookbook.ContextObject.SincethereturnvalueofgetAttribute()istypedtoObject,thecodemustcasttheresulttoContextObject.
Example16-11.ThetargetofRequestDispatcher.forwardhasaccesstotherequestattribute
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassRequestDisplayextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throws
ServletException,java.io.IOException{
ContextObjectobj=(ContextObject)request.getAttribute(
"com.jspservletcookbook.RequestObject");
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>RequestAttribute</title></head><body>");
out.println("<h2>Requestattributevalues</h2>");
//displaythekeysofthejava.util.Mapstoredintherequestobject
//attribute
if(obj!=null)
out.println(obj.getValues());
out.println("</body></html>");
}//enddoGet
}
MakesuretocheckwhethertheServletRequest.getAttribute()returnvalueisnullbeforecallinganyoftheobjectattribute'smethods.ThegetAttribute()methodreturnsnulliftherequestdoesnotcontainanattributeofthespecifiedname.
SeeAlso
Recipe16.1-Recipe16.4onhandlingServletContextattributesinservletsandJSPs;Recipe16.5-Recipe16.8onhandlingsessionattributesinservletsandJSPs;Recipe16.10onsettingrequestattributesinJSPs;Recipe16.11andRecipe16.12onaccessingorremovingrequestattributesinservletsandJSPs;theJavadocforjavax.servlet.ServletRequestAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletRequestAttributeListener.html
Recipe16.10SettingRequestAttributesinJSPs
Problem
YouwanttosetarequestattributeusingaJSP.
Solution
UsetheJSTLcoretagsandthejsp:useBeanstandardactiontocreateaninstanceofanobjectandbindittotherequest.
Discussion
TheJSPinExample16-12storesacom.jspservletcookbook.ContextObjectintherequestscopebyfirstcreatinganinstanceofthatobjectwithjsp:useBean.AsinRecipe16.2andRecipe16.6,thecodeusesthec:settagtobindtheobjecttotherequest,butthistimegivesitsscopeattributeavalueofrequest.
YoushouldstoretheclassesfortheobjectsthatJSPsuseasrequestattributesinWEB-INF/classes,orinWEB-INF/libiftheclassispartofaJARfile.
TheJSPinExample16-12isexactlyliketheJSPcodeshowninRecipe16.2andRecipe16.6,exceptthistimethecodeusestherequestScopeimplicitobjecttofetchtherequestattributeandgiveitanewpropertyandvalue.TherequestScopeisusedinELsyntax(seeChapter23)toaccessrequestattributes.
Example16-12.SettingarequestattributeandforwardingtherequestinaJSP
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="contextObj"class=
"com.jspservletcookbook.ContextObject"/>
<jsp:useBeanid="date"class="java.util.Date"/>
<c:setvar="com.jspservletcookbook.ContextObject"value=
"${contextObj}"scope="request"/>
<c:settarget=
"${requestScope[\"com.jspservletcookbook.ContextObject\"].map}"value=
"${date}"property="${pageContext.request.remoteAddr}"/>
<jsp:forwardpage="/displayAttr"/>
Aftersettingtherequestattributeandgivingitsomevalues,theJSPforwardstherequesttotheservletpath/displayAttr.TheservletorJSPmappedtothatpathhasaccesstothenewrequestattribute.
SeeAlso
Chapter23onusingtheJSTL;Recipe16.1-Recipe16.4onhandlingServletContextattributesinservletsandJSPs;Recipe16.5-Recipe16.8onhandlingsessionattributesinservletsandJSPs;Recipe16.11andRecipe16.12onaccessingorremovingrequestattributesinservletsandJSPs;theJavadocforjavax.servlet.ServletRequestAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletRequestAttributeListener.html
Recipe16.11AccessingorRemovingRequestAttributesinServlets
Problem
Youwantaservlettoaccessorremovearequestattribute.
Solution
Usethejavax.servlet.ServletRequest.getAttribute()andjavax.servlet.ServletRequest.removeAttribute()
methods,includingthenameoftheattributeasthemethodparameter.
Discussion
Example16-13isderivedfromthedoGet()methodofExample16-11inRecipe16.9(refertothatclassifyouneedtoreviewthecompletecodeofaservlethandlingrequestattributes).Example16-13getsanobjectattributefromtheHttpServletRequestobject,whichisthedoGet()method'sfirstparameter.
TheservletcontainercreatesanHttpServletRequestobjectandpassesitasthefirstparametertoalloftheHttpServlet'sservicemethods,includingdoGet()anddoPost().
Example16-13callsoneoftheattribute'smethods,thenremovestherequestattribute.
Example16-13.Aservletaccessesandremovesarequestattribute
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
ContextObjectobj=(ContextObject)request.getAttribute(
"com.jspservletcookbook.ContextObject");
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>RequestAttribute</title></head><body>");
//displaytheattribute'sMapkeys
out.println("<h2>Requestattributevalues</h2>");
if(obj!=null)
out.println(obj.getValues());
//Thismethodcallmaynotbenecessaryasrequestattributes
//persistonlyaslongastherequestisbeinghandled,
//accordingtotheServletRequestAPIdocumentation.
request.removeAttribute("com.jspservletcookbook.ContextObject");
out.println("</body></html>");
}//doGet
Iftheattributedoesnotexistintherequest(becauseitwasnotboundtotherequestinthefirstplace),ServletRequest.getAttribute()returnsnull.Makesuretheservletcodechecksforanullvaluebeforeitcallstheobject'smethods.Inaddition,theServletRequest.getAttribute()methodreturnsanObjecttype,soensurethattheservletcodecaststhereturnvaluetothepropertypebeforecallingtheexpectedtype'smethods.
SeeAlso
Recipe16.1-Recipe16.4onhandlingServletContextattributesinservletsandJSPs;Recipe16.5-Recipe16.8onhandlingsessionattributesinservletsandJSPs;Recipe16.12onaccessingorremovingrequestattributesinJSPs;Chapter6onincludingcontentinservletsandJSPs;theJavadocforjavax.servlet.ServletRequestAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletRequestAttributeListener.html
Recipe16.12AccessingorRemovingRequestAttributesinJSPs
Problem
YouwanttouseaJSPtoaccessorremovearequestattribute.
Solution
UsetheJSTLcoretagsc:outandc:removetoaccessandoptionallyremovetheattribute.
Discussion
Example16-14accessesanobjectattributethatisboundtotheHttpServletRequest.TheJSPaccessesthisattributebyusingELsyntaxinsidethec:outJSTLtag.
Example16-12inRecipe16.10forwardsarequestattributetoaservletusingthejsp:forwardstandardaction.TheJSPinthatexamplecanforwarditsrequestattributetotheJSPinExample16-14byusingthecode:
<jsp:forwardpage="/requestDisplay.jsp"/>
Thecode:
"${requestScope[\"com.jspservletcookbook.ContextObject\"].
values}"
usestherequestScopeJSTLimplicitobject.Thisvariable,whichthe
JSTLautomaticallymakesavailabletoEL-relatedcode,isajava.util.Maptypecontaininganyattributesboundtotherequestscope.Thecodethendisplaysthevaluestheattributecontainsbyaccessingtheobjectattribute'svaluesproperty(seeRecipe16.1foradiscussionoftheobjectusedforstoringanattributeinvariousscopesthroughoutthischapter).
Example16-14.AccessingandremovingarequestattributewiththeJSTL
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>RequestreadingJSP</title></head>
<body>
<h2>HerearethevaluesfromtheboundRequestObject</h2>
<c:outvalue=
"${requestScope[\"com.jspservletcookbook.ContextObject\"].
values}"escapeXml="false"/>
<%--c:removemaynotbenecessaryasrequestattributespersistonlyaslongasthe
requestisbeinghandled--%>
<br>Removingrequestattributewithc:remove...<c:removevar=
"com.jspservletcookbook.ContextObject"scope="request"/>
</body>
</html>
Thec:removetagremovestheattributenamedinitsvarattributefromthespecifiedscope.Usescope="request"becauseyouareremovingthisattributefromtheJSP'srequestscope.Figure16-2showstheoutputofthedisplayRequest.jsppageinawebbrowser.
Figure16-2.Thebrowserdisplayafteraccessingand
removingarequestattributeinaJSP
TheJSPthatappearsinthebrowser'saddressfield,requestBind.jsp,actuallysettheattributeandforwardedtherequest(seeRecipe16.10).Whencodeusesjsp:forward,theoriginalJSPremainsinthebrowser'saddressfield,eventhoughthebrowserdisplaystheoutputoftheJSPtargetedbytheforwardaction.
SeeAlso
Chapter23onusingtheJSTL;Recipe16.1-Recipe16.4onhandlingServletContextattributesinservletsandJSPs;Recipe16.5-Recipe16.8onhandlingsessionattributesinservletsandJSPs;Recipe16.11onaccessingorremovingrequestattributesinservlets;theJavadocforjavax.servlet.ServletRequestAttributeListener:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletRequestAttributeListener.html
Chapter17.EmbeddingMultimediainJSPs
Introduction
Recipe17.1.EmbeddinganAppletinaJSPUsingjsp:plugin
Recipe17.2.EmbeddinganAppletinaJSPUsingtheHTMLConverter
Recipe17.3.AutomaticallyCreatingHTMLTemplateforIncludingFlashFiles
Recipe17.4.WritingHTMLTemplatetoEmbedaFlashFile
Recipe17.5.EmbeddingFlashinaServlet
Recipe17.6.EmbeddingaQuickTimeMovieinaJSP
Recipe17.7.EmbeddinganSVGFileinaJSP
Recipe17.8.EmbeddingaBackgroundSoundtrackinaJSP
Introduction
Mostwebsitesincludesometypeofmultimediaandinteractiveprograms,suchasdigitalvideos,digitalaudiofiles,MacromediaFlashmovies,andJavaapplets.Therefore,JavawebsitesoftenintegratethistypeofcontentwithservletsandJavaServerPages(JSPs).ThischapterexplainsthebasicsofembeddingmultimediainJavawebcomponents.Thisprocessinvolvesincludingtheobjectandembedtagsinyourcomponent'sHTMLoutput.
AJSPisthepreferredchoiceforcombiningmultimediawithdynamiccontent,becauseyoucanmakethetagsthatyouusetoembedthemultimediaapartoftheJSP'sHTMLtemplatetext.However,Recipe17.5alsoshowshowtoincludemultimediaaspartofaservlet'soutput.
Ifthepagecontainingthemultimediacontentdoesnothavetoincludeanyothertypeofdynamicoutput,justuseastaticHTMLpageinsteadofexecutingJSPsandservlets.AstaticpagetypicallyrequiresfewerserverresourcestorespondtoHTMLpagerequests.
Recipe17.1EmbeddinganAppletinaJSPUsingjsp:plugin
Problem
Youwanttousethejsp:pluginstandardactiontoexecuteaJavaappletwiththeJavaPlug-insoftware.
Solution
Usethejsp:pluginactionpositionedintheareaofaJSPwhereyouwanttheapplettoappear.
Discussion
TheJSPspecificationprovidesastandardaction,jsp:plugin,whichproducestheobjectandembedtagsthataredesignedtoallowbrowserstoloadaJavaapplet.TheactionwillruntheappletusingSunMicrosystems'sJavaPlug-inorinitiatethedownloadofthePlug-iniftheuserhasnotyetinstalledthePlug-in.
TheJavaPlug-inisdesignedtoexecuteanappletusingSunMicrosystems'sJava2RuntimeEnvironment,ratherthananyJavaruntimeprovidedbythebrowser.TheinstallationoftheJavaJREorSoftwareDevelopmentKitautomaticallyinstallstheJavaPlug-in.
Usenestedjsp:paramelementstoprovidetheappletwithany
necessaryparameterandvaluepairs.Thejsp:paramelementsmustbenestedwithinasinglejsp:paramselement.
Example17-1showsaJSPfilethatusesjsp:plugintoembedanappletnamedClock.class.Inthiscase,theClock.classfileislocatedinthesamedirectoryastheJSPinExample17-1.
ThisappletoriginatesfromSunMicrosystems'ssampleapplets:http://java.sun.com/products/plugin/1.4.1/demos/plugin/applets/Clock/example1.html
Example17-1.EmbeddingaJavaappletwithjsp:plugin
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="date"class="java.util.Date"/>
<html>
<head><title>AClockinaJSP</title></head>
<body>
<h2>Thetime...</h2>
<jsp:plugintype="applet"code="Clock.class"codebase=
"http://localhost:8080/home/applets"jreversion="1.4.1">
<jsp:params>
<jsp:paramname="scriptable"value="false"/>
</jsp:params>
<jsp:fallback>
Sorry,weareunabletostarttheJavaplugin<br/>
</jsp:fallback>
</jsp:plugin>
<br/><c:outvalue="${date}"/>
</body>
</html>
UserswhohaveinstalledInternetExplorerforWindowsdependonanHTMLobjecttagtoprovidethedirectionforloadingtheapplet.InbrowsersthatsupporttheNetscape-styleplug-in,theHTMLusesit'sembedtag.Thejsp:pluginstandardactiongeneratesHTMLthatshouldworkwithbothbrowsertypes(butyoustillshouldtesttheresultingJSP,ofcourse).
Example17-2showstheHTMLtagsgeneratedbythejsp:pluginactionwhentheInternetExplorer5.5andtheNetscapebrowsersrequesttheJSPinExample17-1.
Example17-2.HTMLtagsgeneratedbythejsp:pluginactionforloadingaJavaapplet
<OBJECTclassid=
clsid:8AD9C840-044E-11D1-B3E9-00805F499D93codebase=
"http://java.sun.com/products/plugin/1.2.2/jinstall-1_2_2-win.cab#
Version=1,2,2,0">
<PARAMname="java_code"value="Clock.class">
<PARAMname="java_codebase"value="http://localhost:8080/home/applets">
<PARAMname="type"value="application/x-java-applet;version=1.4.1">
<PARAMname="scriptable"value="false">
<COMMENT>
<EMBEDtype="application/x-java-applet;version=1.4.1"pluginspage=
"http://java.sun.com/products/plugin/"java_code=
"Clock.class"java_codebase=
"http://localhost:8080/home/applets"scriptable="false"/>
<NOEMBED>
Sorry,weareunabletostarttheJavaplugin<br/>
</NOEMBED>
</COMMENT>
</OBJECT>
Figure17-1showstheJSPwiththeembeddedapplet.
Figure17-1.AJSPwithanembeddedapplet
SeeAlso
TheJavaPlug-intechnologypage:http://java.sun.com/products/plugin/;
Recipe17.2onembeddinganappletusingtheSunMicrosystemsHTMLConverter.
Recipe17.2EmbeddinganAppletinaJSPUsingtheHTMLConverter
Problem
YouwanttousetheJavaPlug-inHTMLConvertertooltogeneratethetagsforembeddinganapplet.
Solution
UsetheHTMLConvertertoolwithinhtmlconverter.jar,whichislocatedinthelibdirectoryofthedirectorywhereyouhavetheJavaSDKinstalled.
Discussion
AbusydevelopercanlettheJavaPlug-inHTMLConvertertoolproducetheHTMLtagsthatareresponsibleforloadingJavaapplets.TheJavaPlug-inisaJava-basedtoolthatallowsappletstoberunintheSunMicrosystemsJava2runtimeenvironment,ratherthanwithinthewebbrowser'sJavaruntimeenvironment.TheJavaPlug-inisinstalledonyourmachinewhenyouinstalltheJRE,includingtheinstallationoftheSDK.
TheHTMLConvertertoolwillconvertaspecifiedJSPfilethatcontainsanappletHTMLtag,replacingtheapplettagwithamorecomplextagcollectionthatallowsmostbrowserstoloadtheJavaapplet.TheConverterleavestherestofyourJSPcodeuntouched;itonlyreplacestheJSP'sapplettag.
HereishowtousetheHTMLConvertertool:
1. WritetheJSPfile,addinganapplettag.Example17-3showsaJSPthatembedsaClock.classappletreference.ThisJSP,ratherredundantly,dynamicallywritesatimestringbeneaththeapplet.IincludedthiscodetoshowthattheConverterdoesnotchangetheJSPcode;itjustalterstheapplettagtemplatetextincludedwiththeJSP.
Example17-3.AJSPwithanapplettag
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="date"class="java.util.Date"/>
<html>
<head><title>AClockinaJSP</title></head>
<body>
<h2>Thetime...</h2>
<appletcode="Clock.class"codebase="http://localhost:8080/home/applets">
</applet>
<br/><c:outvalue="${date}"/>
</body>
</html>
Openacommand-linewindowtothelibdirectoryofyourSDKinstallation,suchasH:\j2sdk1.4.1_01\lib.
Typejava-jarhtmlconverter.jar-gui.ThiscommandlaunchestheSwingversionoftheHTMLConvertertool.Figure17-2showswhatthetoollookslike.
Figure17-2.TheHTMLConverter(GUIversion)
TheHTMLConvertercanalsoberunfromthecommandline.SeetheJavaPlug-inDeveloperGuideforsupportedoptions:http://java.sun.com/j2se/1.4.1/docs/guide/plugin/.
4. Ifyouwanttochooseaback-upfolderwherethetoolsavestheoldJSPfile(withtheapplettag),usetheHTMLConverterGUIwindowtochoosethisfolder.
Clickthe"Convert..."buttonwiththeJSPfilespecifiedinthetoptextfield,andtheConverterwilloverwritetheoriginalfilewithadditionalobjectandembedtags.
Example17-4showsthecodethatreplacedtheapplettaginExample17-3(inboldfont),aswellasthecodethattheconvertertooldidnotmodify.
Example17-4.TheobjectandembedtagsproducedbytheHTMLConverter
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="date"class="java.util.Date"/>
<html>
<head><title>AClockinaJSP</title></head>
<body>
<h2>Thetime...</h2>
<!--"CONVERTED_APPLET"-->
<!--HTMLCONVERTER-->
<OBJECT
classid=
"clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
codebase=
"http://java.sun.com/products/plugin/autodl/jinstall-1_4-windows-
i586.cab#Version=1,4,0,0"
>
<PARAMNAME=CODEVALUE="Clock.class">
<PARAMNAME=CODEBASEVALUE="http://localhost:8080/home/applets">
<PARAMNAME="type"VALUE="application/x-java-applet;version=1.4">
<PARAMNAME="scriptable"VALUE="false">
<COMMENT>
<EMBED
type="application/x-java-applet;version=1.4"
CODE="Clock.class"
JAVA_CODEBASE="http://localhost:8080/home/applets"
scriptable=false
pluginspage=
"http://java.sun.com/products/plugin/index.html#download">
<NOEMBED>
</NOEMBED>
</EMBED>
</COMMENT>
</OBJECT>
<!--
<APPLETCODE="Clock.class"JAVA_CODEBASE=
"http://localhost:8080/home/applets">
</APPLET>
-->
<!--"END_CONVERTED_APPLET"-->
<br/><c:outvalue="${date}"/>
</body>
</html>
UsersmayhavetroubleloadingtheappletintheirbrowsersiftheyhaveseveralinstalledversionsoftheJavaPlug-in.ThisoccurswhenuserssteadilyupgradetheirJREorJavaSDKversions,whichinstallthecorrespondingversionoftheJavaPlug-in.ThesimplestsolutioninthesecasesistouninstalltheoldJavaPlug-ins.
SeeAlso
TheJavaPlug-intechnologypage:http://java.sun.com/products/plugin/;Recipe17.1onembeddingaJavaappletusingthejsp:pluginstandardJSPaction.
Recipe17.3AutomaticallyCreatingHTMLTemplateforIncludingFlashFiles
Problem
YouwanttoautomaticallygeneratetherequiredHTMLforembeddingaFlashfileinawebcomponent.
Solution
FromwithinMacromediaFlash6,usethe"File Publish"menucommandtooutputanHTMLfilethatincludestheobjectandembedtags.
Discussion
Withan.swffileopeninMacromediaFlash6,usethe"File Publish"menucommandtocreateanHTMLfile.ThisfileincludesthenecessarytagstoembedtheFlashmovieyouareworkingoninawebcomponent.ThencutandpastethesetagsandattributesintoyourJSP.Example17-5showstheoutputfromusingthismenucommandwithan.swffilenamedexample.swf.
Example17-5.AutomaticallygeneratedtemplatetextfromwithintheFlashapplication
<HTML>
<HEAD>
<metahttp-equiv=Content-Typecontent="text/html;charset=ISO-8859-1">
<TITLE>example</TITLE>
</HEAD>
<BODYbgcolor="#FFFFFF">
<!--URL'susedinthemovie-->
<!--textusedinthemovie-->
<!--DeductionsPaycheckSDIAnnualSalaryMedicareSocial
securityESPP401k$#%FederalStateMarriedSingleactions-->
<OBJECTclassid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase=
"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.
cab#version=6,0,0,0"WIDTH="550"HEIGHT="400"id="example"ALIGN=""
>
<PARAMNAME=movieVALUE="example.swf">
<PARAMNAME=qualityVALUE=high><PARAMNAME=bgcolorVALUE=#FFFFFF>
<EMBEDsrc="example.swf"quality=highbgcolor=#FFFFFFWIDTH="550"HEIGHT=
"400"NAME="example"ALIGN=""
TYPE="application/x-shockwave-flash"PLUGINSPAGE=
"http://www.macromedia.com/go/getflashplayer">
</EMBED>
</OBJECT>
</BODY>
</HTML>
YourJSPprobablyalreadyincludestheboilerplateHTMLsuchasthebodytag;therefore,youonlyhavetocutandpastethenoncommented,emphasizedcodeinExample17-5.
Theexample.swffileresidesinthesamedirectoryastheHTMLfileinthisexample.
Example17-6inthenextrecipeshowsaJSPfilewiththesametypeofFlash-relatedobjectandembedtagsasthoseillustratedinthisrecipe.Figure17-3showstheautomaticallygeneratedHTMLfilefromExample17-5.
Figure17-3.HTMLtemplatetextwithanembeddedFlashfile
ThedisplayedFlashmovieisderivedfromoneoftheFlashsamplesthataccompaniestheFlash6application:Paycheck_calculator.swf.
SeeAlso
Macromediatechnicalnotespage:http://www.macromedia.com/support/flash/technotes.html;anarticleaboutalternativetechniquestousingtheembedtag:http://www.macromedia.com/devnet/mx/dreamweaver/articles/flash_satay.html
Recipe17.4WritingHTMLTemplatetoEmbedaFlashFile
Problem
YouwanttowritetheHTMLtemplatetexttoembedaFlashfileinyourJSP.
Solution
UsetheobjectandembedtagssothattheHTMLisreadcorrectlybythebrowsersthatsupporteitherofthesetags.
Discussion
YoumaynothavetheMacromediaFlashapplicationthatcanautomaticallygeneratetheHTMLwhichisnecessarytoembedaFlashfile(Recipe17.4).Inthiscase,writetherequiredHTMLtemplatetextforembeddingaFlashmovieinsideaJSP.
Example17-6showsaJSPwithanembeddedFlashfile(theembeddedfilehasa.swfextension).Thesameconceptappliestothisexampleastotheotherrecipes:theobjecttagisfortheInternetExplorerWindowsbrowser,whichembedsthemediafileasanActiveXcontrol,notaNetscape-styleplug-in.Theembedtag,nestedinsidetheobjecttag,isdesignedtoembedtheFlashfileinNetscapeandotherbrowsersthatsupportNetscape-styleplug-ins.
Example17-6isderivedfromatechnicalnoteathttp://www.macromedia.com/support/flash/technotes.html.
Example17-6.AJSPcontainsanembeddedfile
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="date"class="java.util.Date"/>
<html>
<head><title>FlashinaJSP</title></head>
<body>
<h2>EnjoytheFlashMovie</h2>
<OBJECTCLASSID=
"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"CODEBASE=
"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#
version=6,040,0"width="293"height="423"
>
<PARAMname="movie"VALUE="coolFlashMov.swf">
<PARAMname="quality"VALUE="high">
<PARAMname="bgcolor"VALUE="#FFFFFF">
<EMBEDSRC=
"coolFlashMov.swf"quality="high"width="293"height="423"
bgcolor="#FFFFFF"type="application/x-shockwave-flash"PLUGINSPAGE=
"http://www.macromedia.com/go/getflashplayer"
>
</EMBED>
</OBJECT>
<br/><c:outvalue="${date}"/>
</body>
</html>
BoththeembedandobjecttagsaredesignedtoprompttheendusertodownloadtherequiredversionoftheFlashplug-inorActiveXcontroliftheydonotalreadyhaveitinstalled.
SeeAlso
Macromediatechnicalnotespage:http://www.macromedia.com/support/flash/technotes.html;anarticleaboutalternativetechniquestousingtheembedtag:http://www.macromedia.com/devnet/mx/dreamweaver/articles/flash_satay.html
Recipe17.5EmbeddingFlashinaServlet
Problem
YouwanttoembedaFlashfileinaservlet'soutput.
Solution
Usethejavax.servlet.RequestDispatcher.include(request,response)
methodinthedoGet()methodoftheservletthatincludesthenecessaryHTMLtemplatetext.
Discussion
TheservletcanincludetheHTMLfragmentthatloadstheFlashmovieintothepagebyusingaRequestDispatcher.Thisprocessissimilartoserver-sideincludesintraditionalCommonGatewayInterface(CGI)programs.Whentheservletreceivesarequest,itincludesthetextfragmentcontainingtheFlash-relatedtagsinitsHTMLoutput.ThisdesignseparatestheservletitselffromthetagsandparametersthatloadtheFlashmovie,sothateachoftheseentitiesevolvesindependently.Forexample,youcanchangethefilenameoftheFlashmovieorsomeoftheobjectorembedparameterswithoutrecompilingtheservletcode.
Example17-7isaservletthatusesaRequestDispatchertoincludethetextshowninExample17-8.Thetextappearsinaflash.txtfilethatisstoredatthetoplevelofthewebapplication.
RequestDispatcherstypicallyincludetheoutputofservletsandJSPs,notjust
textfragments.SeeChapter6formoredetailedRequestDispatcher-relatedrecipes.
Example17-7.AservletusesaRequestDispatchertoincludeobjectandembedtags
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassFlashServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>EmbeddedFlashcontent</title></head><body>");
RequestDispatcherdispatcher=request.getRequestDispatcher(
"/flash.txt");
dispatcher.include(request,response);
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
doGet(request,response);
}//doPost
}
Example17-8showsthetextfragmentincludedbytheservletinExample17-7.
Example17-8.Anincludedtextfragment(flash.txt)thataservletusestoembedFlash
<OBJECTclassid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"codebase=
"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#
version=6,0,0,0"WIDTH="550"HEIGHT="400"id="example"ALIGN=""
>
<PARAMNAME=movieVALUE="/home/example.swf">
<PARAMNAME=qualityVALUE=high>
<PARAMNAME=bgcolorVALUE=#FFFFFF>
<EMBEDsrc="/home/example.swf"quality=highbgcolor=#FFFFFFWIDTH=
"550"HEIGHT="400"NAME="example"ALIGN=""TYPE=
"application/x-shockwave-flash"PLUGINSPAGE=
"http://www.macromedia.com/go/getflashplayer">
</EMBED>
</OBJECT>
TheresultinawebbrowserlooksexactlylikeFigure17-3.
SeeAlso
Chapter6ondynamicallyincludingcontentintoservlets;Macromedia
technicalnotespage:http://www.macromedia.com/support/flash/technotes.html;anarticleaboutalternativetechniquestousingtheembedtag:http://www.macromedia.com/devnet/mx/dreamweaver/articles/flash_satay.html
Recipe17.6EmbeddingaQuickTimeMovieinaJSP
Problem
YouwanttoembedaQuickTimemovieinyourJSP.
Solution
Usetheembedtagnestedinsidetheobjecttag.TheobjecttaghastocontaintheCLASSIDattributewiththepropervalue.
Discussion
SimilartousingtheJavaPlug-in,aJSPusestheembedtaginsideofanHTMLobjecttagtoproperlyloadoneofAppleComputer'sQuickTimemovies.YoumustincludetheCLASSIDattributevalueexactlyasExample17-9specifies.YoualsomustincludethesameCODEBASEattributevalue.IftheuserhasanInternetExplorerWindowsbrowser,buthasnotyetinstalledtheQuickTimeActiveXcontrol,theCODEBASEattributevaluespecifieswheretheusercandownloadit.
Example17-9.EmbeddingaQuickTimemovieinaJSP
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="date"class="java.util.Date"/>
<html>
<head><title>QuickTimeinaJSP</title></head>
<body>
<h2>LadiesandGentlemen,TheWho</h2>
<OBJECTCLASSID=
"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"WIDTH="320"
HEIGHT="256"CODEBASE="http://www.apple.com/qtactivex/qtplugin.cab">
<PARAMname="SRC"VALUE="http://www.parkerriver.com/films/who_bene2.mov">
<PARAMname="AUTOPLAY"VALUE="true">
<PARAMname="CONTROLLER"VALUE="true">
<EMBEDSRC=
"http://www.parkerriver.com/films/who_bene2.mov"
WIDTH="240"HEIGHT="196"
AUTOPLAY="true"CONTROLLER=
"true"PLUGINSPAGE="http://www.apple.com/quicktime/download/">
</EMBED>
</OBJECT>
<br/><c:outvalue="${date}"/>
</body>
</html>
IfthebrowserusesNetscape-styleplug-ins,thentheembedtagwillinitiatetheloadingoftheQuickTimemovie.TheJSPinExample17-6properlyloadedthemovieintotheSafariwebbrowseronmyMacintoshlaptop,forinstance.Oneoftheadvantagesoftheembedtagisthatyoucanuseanumberofproprietaryattributesthattheembeddedobject,suchasQuickTime,understands.Example17-9specifiesthatthemovieshouldstartplayingassoonasthebrowserhasloadedenoughdata(AUTOPLAY="true")aswellasthatthebrowsershouldshowthemovie
controls,whichletstheuserstoporstartthemovie(CONTROLLER="true").
Figure17-4showstheQuickTimemovieembeddedintheJSPofExample17-9.
Figure17-4.AQuickTimemovieembeddedinaJSP
SeeAlso
AppleComputer'sguideonembeddingQuickTimeinWebpages:http://www.apple.com/quicktime/authoring/embed.html;Recipe17.3-Recipe17.5onembeddingaFlashfile;Recipe17.7onembeddinganSVGfileinaJSP;Recipe17.8onembeddingabackgroundsoundtrack.
Recipe17.7EmbeddinganSVGFileinaJSP
Problem
YouwanttodisplayaScalableVectorGraphics(SVG)imageinsideaJSP.
Solution
UsetheembedHTMLelementtopositiontheSVGintheJSP.
Discussion
DeveloperstypicallyusetheembedtagtoplaceanSVGfileinanHTMLfileorJSP.SVGisanXML-basedgraphicstechnologythatprovidesdevelopersanddesignersleverageinproducinganddisplayinginteractivegraphics.
BrowsersusespecialSVGviewerapplicationstohandletheembeddedSVGfiles.AdobeSystem'sSVGViewerapplicationcanbedownloadedfromhttp://www.adobe.com/svg/viewer/install/.Corel'sSVGViewercanbedownloadedfromhttp://www.corel.com/svgviewer/.
Example17-10embedsanSVGfilenamedtestLogo.svgandpointstheusertotheAdobeSVGViewerdownloadsiteiftheyhavenotinstalledanSVGViewerapplication.
SVGfileshaveextensionsofeither.svgor(incompressedform).svgz,eventhoughtheyareXMLfiles.
Example17-10.AnSVGgraphicsfileembeddedinaJSP
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="date"class="java.util.Date"/>
<html>
<head><title>SVGinaJSP</title></head>
<body>
<h2>AScalableVectorGraphicsexample</h2>
<embedsrc=
'<c:outvalue="${param.svg_source}"/>.svg'width=
"200"height="200"type="image/svg-xml"pluginspage=
"http://www.adobe.com/svg/viewer/install/"
>
<br/><c:outvalue="${date}"/>
</body>
</html>
Example17-10showshowtoplaceanSVGwithinotherJSPcodeelements,suchasthetaglibdirectiveandthejsp:useBeanstandardaction.Example17-10alsodynamicallyloadsanSVGbasedontherequestparameternamedsvg_source.ThecodeusestheJSTLc:outtagandtheEL'sparamimplicitobjecttooutputtheparametervalue(seeChapter23ontheJSTL).
Figure17-5showstheresultofrequestingtheJSPinExample17-10,includingthenameoftheSVGfileasarequestparameter.Therequest
URLlookslike:
http://localhost:8080/home/svg.jsp?svg_source=testLogo
Figure17-5.AJSPpageshowsanSVGgraphicsfile
TheSVGshowninFigure17-5isderivedfromAdobeSystemsInc.,whichcreatestheAdobeSVGViewerandanSVG-enabledgraphicsapplication,AdobeIllustrator.
SeeAlso
SVGspecificationsattheW3Consortium:http://www.w3.org/Graphics/SVG/Overview.htm8;Adobe'sSVGViewerinstallpage:http://www.adobe.com/svg/viewer/install/;Recipes17-3-5onembeddingaFlashfileinservletsandJSPs;Recipe17.6onembeddingaQuickTimemovieinaJSP.
Recipe17.8EmbeddingaBackgroundSoundtrackinaJSP
Problem
YouwanttoembedanaudiofileinyourJSP.
Solution
UsetheembedtagintheJSP.Usethehiddenattributeifyouwanttohidetheaudiocontrols;otherwise,specifyawidthandheightattributeforshowingtheaudiocontrols.
Discussion
TheembedtagisusedtoincludeanaudiofilewithaJSP,sothatwhenauserrequeststheJSP,thebrowserplaysmusic.Specifically,thebrowserisdesignedtodetecttheMIMEtypeoftheembeddedfile,thenactivateahelperapplicationsuchasQuickTimeorRealAudiotohandletheembeddedfileandplaythemusic.
Example17-11showsaJSPthatembedsanMPEG,audiolayer3(MP3)file.TheJSPdisplayssomeinformationabouttheartistbasedonarequestparameter;thisrandominformationisincludedtoshowhowtocombineJSPcodewiththeembedtag.Theembedtagincludeswidthandheightattributestoshowtheaudiocontrolsinthewebpage.Thecontrolsallowtheusertoturnthevolumeoffordowniftheydonotwanttobeserenadedwhilesurfing.
Example17-11.AJSPwithanembeddedaudiofile
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<c:setvar="artist"value="${param.artist}"/>
<html>
<head><title>ChooseYourTunes</title></head>
<body>
<h2>Youchosemusicfromtheartist<c:outvalue="${artist}"/></h2>
<embedsrc="ConstantCraving.mp3"width="240"height="160">
</embed>
</body>
</html>
Figure17-6showstheoutputfromtheJSPinExample17-11.
Figure17-6.EmbeddedsongfilecontrolsinaJSP
SeeAlso
Recipe17.1andRecipe17.2onembeddingaJavaappletinaJSP;
Recipe17.3-Recipe17.5onembeddingaFlashfileinaJSP;Recipe17.6onembeddingaQuickTimemovie;Recipe17.7onembeddinganSVGfile.
Chapter18.WorkingWiththeClientRequest
Introduction
Recipe18.1.ExaminingHTTPRequestHeadersinaServlet
Recipe18.2.ExaminingHTTPRequestHeadersinaJSP
Recipe18.3.UsingaFiltertoAlterRequestHeaders
Recipe18.4.AutomaticallyRefreshingaServlet
Recipe18.5.AutomaticallyRefreshingaJSP
Recipe18.6.CountingtheNumberofWebApplicationRequests
Introduction
Anumberofwebapplicationsmustexaminetheclientrequestbeforesendingaresponse.Anexampleisaservletthathastoread(orsniff)thebrowsertype(oftenthroughtheUser-Agentheader).ServletsorotherwebcomponentsreadinformationabouttherequestbyexaminingHTTPrequestheaders.Theseheadersarecomposedofheadernamesfollowedbycoloncharactersandtheirvalues,suchasAccept-Language:en.Theheadersprecedeanymessagebodythattheclientissendingtotheserver,suchastextthathasbeenpostedfromanHTMLform.
HereisanexampleofagroupofrequestheaderssentwitharequestforaJSPnamedcontextBind.jsp:
GET/home/contextBind.jspHTTP/1.1
User-Agent:Opera/5.02(WindowsNT4.0;U)[en]
Host:localhost:9000
Accept:text/html,image/png,image/jpeg,image/gif,image/x-xbitmap,*/*
Accept-Language:en
Accept-Encoding:deflate,gzip,x-gzip,identity,*;q=0
Cookie:mycookie=1051567248639;JSESSIONID=1D51575F3F0B17D26537338B5A29DB1D
Connection:Keep-Alive
TherecipesinthischaptershowhowtoexaminerequestheaderswithservletandJSPs,usefilterstoalterrequests,automaticallyrefreshservletsandJSPs,andcountthenumberofapplicationrequests.
Recipe18.1ExaminingHTTPRequestHeadersinaServlet
Problem
YouwanttoexaminetheHTTPrequestheadersinaservlet.
Solution
Usethejavax.servlet.http.HttpServletRequest.getHeaderNames(
)andgetHeader()methodstoaccessthenamesandvaluesofvariousrequestheaders.
Discussion
TheHttpServletRequest.getHeaderNames()methodreturnsalloftherequestheadernamesforanincomingrequest.YoucanthenobtainthevalueofaspecificheaderbyprovidingtheheadernametothemethodHttpServletRequest.getHeader()method.Example18-1getsanEnumerationofheadernamesintheservlet'sdoGet()method,andthendisplayseachheaderandvalueonitsownlineintheresultingHTMLpage.
Example18-1.Aservletdisplaysrequestheadersandvalues
packagecom.jspservletcookbook;
importjava.util.Enumeration;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassRequestHeaderViewextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//getanEnumerationofalltherequestheadernames
Enumerationenum=request.getHeaderNames();
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>RequestHeaderView</title></head><body>");
out.println("<h2>RequestHeaders</h2>");
Stringheader=null;
//displayeachrequestheadernameandvalue
while(enum.hasMoreElements()){
header=(String)enum.nextElement();
//getHeaderreturnsnullifarequestheaderofthatnamedoesnot
//existintherequest
out.println("<strong>"+header+"</strong>"+":"+
request.getHeader(header)+"<br>");
}
out.println("</body></html>");
}//doGet
}
Figure18-1showstheRequestHeaderViewservlet'soutput.
Figure18-1.Aservletshowstherequestheadernamesandvalues
SeeAlso
Recipe18.2onexaminingrequestheadersinaJSP;Recipe18.3onusingafiltertowraptherequestandforwarditalongthefilterchain;Recipe18.6onusingalistenertotrackrequests;Chapter7onhandlingrequestparametersandJavaBeanpropertieswithservlets,JSPs,andfilters.
Recipe18.2ExaminingHTTPRequestHeadersinaJSP
Problem
YouwanttouseaJSPtodisplaytherequestheadersandvalues.
Solution
Usethec:forEachandc:outJSTLtagstoviewtheheadernamesandvalues.
Discussion
TheJSTLv1.0makesallexistingrequestheadersavailableviatheheaderimplicitobject.TheJSTLautomaticallymakesthisvariableavailabletoJSPs;theheaderobjectevaluatestoajava.util.Maptype.
InExample18-2,thec:forEachtagiteratesoverthisMapandstoreseachheadernameandvalueintheloopvariablenamedbyc:forEach'svarattribute(inExample18-2it'scalledreq).Thec:forEachvarattributeisimplementedasajava.util.Map.Entrytype,whichisadatatypethatstoreskeysandtheirvalues.Thec:outtagdisplayseachheadernamebyusingELformat:${req.key}.Consequentlyc:outdisplaysthevaluewith${req.value}.
Example18-2.Viewingtherequestheadernamesand
valuesinaJSP
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>RequestHeaders</title></head>
<body>
<h2>HerearetheRequestHeadernamesandvalues</h2>
<c:forEachvar="req"items="${header}">
<strong><c:outvalue=
"${req.key}"/></strong>:<c:outvalue="${req.value}"/><br>
</c:forEach>
</body>
</html>
Figure18-2showstheresultinabrowserofrequestingthedisplayHeaders.jsppage.
Figure18-2.AJSPpageshowsrequestheadersusingJSTLtags
SeeAlso
Chapter23onusingtheJSTL;Recipe18.2onexaminingrequestheadersinaservlet;Recipe18.3onusingafiltertowraptherequestandforwarditalongthefilterchain;Recipe18.6onusingalistenertotrackrequests;Chapter7onhandlingrequestparametersandJavaBeanpropertieswithservlets,JSPs,andfilters.
Recipe18.3UsingaFiltertoAlterRequestHeaders
Problem
YouwanttouseafiltertochangetherequestheadersbeforeaservletorJSPreceivestherequest.
Solution
Wraptherequestinyourowncustomrequestclass.PasstherequestwrapperordecoratorclasstotheFilterChain.doFilter()method,insteadoftheoriginalrequestdestination.
Discussion
Thejavax.servlet.http.HttpServletRequestWrapperisaconvenienceclassthatyoucanextendtoprovideadditionalfunctionalityforanHTTPrequest.Hereishowtoalterandforwardarequestusingafilter:
1. CreateaclassthatextendsHttpServletRequestWrapper.
Placethisclassinthewebapplication'sWEB-INF/classes(includingpackage-relateddirectories)directoryorWEB-INF/libiftheclassispartofaJARfile.
Createaclassthatimplementsjavax.servlet.Filter,suchasExample18-3.ThisclassusesyourcustomrequestwrapperclasstoenclosetheServletRequestparameteroftheFilter.doFilter()
method.
StorethefilterclassinWEB-INF/classesorWEB-INF/lib(ifit'sinaJAR).
Registerthefilterinweb.xml.Inthisrecipe,thefilterismappedtoalloftherequestsinthewebapplicationwiththeURLmapping/*.
Example18-3showsthefilterclassthatpassestherequest-wrapperclassalongthefilterchain.ThefileisnamedRequestFilter;thewrapperclassisnamedReqWrapper.
Example18-3.AfilterthatwrapstheHttpServletRequest
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassRequestFilterimplementsFilter{
privateFilterConfigconfig;
/**CreatesnewRequestFilter*/
publicRequestFilter(){}
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
this.config=filterConfig;
}
publicvoiddoFilter(ServletRequestrequest,
ServletResponseresponse,FilterChainchain)throwsjava.io.IOException,
ServletException{
ReqWrapperwrapper=null;
ServletContextcontext=null;
//createtherequestwrapperobject,aninstanceofthe
//ReqWrapperclass.Theclientrequestispassedinto
//ReqWrapper'sconstructor
if(requestinstanceofHttpServletRequest)
wrapper=newReqWrapper((HttpServletRequest)request);
//usetheServletContext.logmethodtologparamnames/values
if(wrapper!=null){
context=config.getServletContext();
context.log("Query:"+wrapper.getQueryString());}
//continuetherequest,responsetonextfilterorservlet
//destination
if(wrapper!=null)
chain.doFilter(wrapper,response);
else
chain.doFilter(request,response);
}//doFilter
publicvoiddestroy(){
/*calledbeforetheFilterinstanceisremoved
fromservicebythewebcontainer*/
}//destroy
}
Example18-3usestheservletcontexttologtheReqWrapper'squerystring.TheReqWrapperclassaddsaparametertothequerystring,but
youcouldmakethisclassimplementwhateverbehavioryouneedinyourownapplication.Example18-4showsthefilter-mappingentriesinthedeploymentdescriptor(web.xml),whichensuresthateveryapplicationrequestpassesthroughthisfilter.
Example18-4.Thefiltermappinginweb.xml
<filter>
<filter-name>RequestFilter</filter-name>
<filter-class>com.jspservletcookbook.RequestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RequestFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
TheReqWrapperisasimpleexampleofanHttpServletRequestWrappersubclassthatencapsulatestheoriginalrequest.ThisclassoverridesthegetQueryString()methodinordertoaddaparametertotherequest'squerystring.
Toaccessthenewfilterparameter,youmustcallgetQueryString()ontherequestonceitreachesitsdestinationservlet,thenparsethegetQueryString()returnvalueforindividualparameters.UsingtheELwillnotworkwithrequestwrappersthatoverridegetQueryString():
//doesnotreturnthenewparametervalue
//addedbytheoverriddengetQueryString
//method
${param.filter}
Therequestthatpassesthroughthefilteristheparameterto
ReqWrapper'sconstructor,sothefilter(inExample18-3)wrapstherequestwiththiscode:
wrapper=newReqWrapper((HttpServletRequest)request);
AURLsenttotheapplicationcontainingthequerystringname=Brucedisplaysthefollowingtextintheserverlog(asaresultoftheServletContext.logmethod):
Query:name=Bruce&filter=com.jspservletcookbook.ReqWrapper.
Example18-5isthecodefortheReqWrapperobject.
Example18-5.TheReqWrapperclassforencapsulatingtheHttpServletRequest
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.HttpServletRequestWrapper;
importjavax.servlet.http.HttpServletRequest;
publicclassReqWrapperextendsHttpServletRequestWrapper{
privatestaticfinalStringAMP="&";
publicReqWrapper(HttpServletRequestrequest){
super(request);
}
publicStringgetQueryString(){
Stringquery=null;
//getthequerystringfromthewrappedrequestobject
query=((HttpServletRequest)getRequest()).getQueryString();
//adda'filter'parametertothisquerystringwiththeclass
//nameasthevalue
if(query!=null)
returnquery+AMP+"filter="+getClass().getName();
else
return"filter="+getClass().getName();
}//getQueryString
}
Themethodcallchain.doFilter(wrapper,response)attheendofExample18-3passestherequest(wrappedinourowncustomclass)andresponsetothenextfilter,ortothedestinationservletorJSPifnootherfiltersareregistered.
SeeAlso
Recipe18.1andRecipe18.2onexaminingrequestheadersinaservletandaJSPrespectively;Recipe18.3onusingafiltertowraptherequestandforwarditalongthefilterchain;Recipe18.6onusingalistenertotrackrequests;Chapter7onhandlingrequestparametersandJavaBeanpropertieswithservlets,JSPs,andfilters.
Recipe18.4AutomaticallyRefreshingaServlet
Problem
Youwanttoautomaticallyrefreshaservlet-generatedpageataspecifiedinterval.
Solution
AddaRefreshresponseheader,usingthejavax.servlet.http.HttpServletResponseobject.
Discussion
SupposethatyourservletismonitoringaRedSoxversusYankeesbaseballgame.Youwanttobeabletoallowausertofollowthegamealmostpitchbypitch,andhaveyourwebapplicationconstantlyupdatethestatusofthegame.IfyouaddaRefreshresponseheadertoyourclientresponse,thebrowserwillcontinuallyrefreshthepageaccordingtothespecifiedinterval.
Example18-6addsaresponseheaderthatthewebcontainerwillsendtotheclientintheformatRefresh:60,whichmeans"requestthispageagainin60seconds."
Example18-6.Refreshingaservletevery60seconds
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassAutoServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//clientbrowserwillrequestthepageevery60seconds
response.addHeader("Refresh","60");
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>ClientRefresh</title></head><body>");
out.println("<h2>WelcometotheRedSox-Yankeesseries...</h2>");
//MoreHTMLordynamiccontent
out.println("</body></html>");
}//doGet
}
Therearesomecaveatstothisapproachiftheenduserwalksawayfromherdesk,herbrowserwillblithelycontinuetorequestthepage.Ifyourservletdoesn'timposesomecontroloverthis,youcouldaddalotofunnecessaryloadtoyourapplication.Oneexampleofasolutiontothisproblemistokeeptrackofhowmanytimestheservlethasbeenrefreshedwithasessionattribute(detailedinChapter16).Ifthenumberoftimesexceedsacertainlimit,youcouldstopaddingtheheadertotheresponse.Example18-7showspartofadoPost()methodbodyforkeepingtrackofauser'srefreshcount.
Example18-7.Trackingauser'srefreshcount
//insidedoPost(ordoGet)method
HttpSessionsession=request.getSession();
Longtimes=(Long)session.getAttribute("times");
//createsessionattributeifitdoesn'texist
if(times==null)
session.setAttribute("times",newLong(0));
//localvariable'temp'willholdthesessionattributevalue
longtemp=1;
//incrementtheattributevaluetoaccountforthisrequest
if(times!=null)
temp=times.longValue()+1;
if(temp<60)//onlyallow60refreshes;aboutanhour'sworth
response.addHeader("Refresh","60");
//updatethesessionattributevalue
session.setAttribute("times",newLong(temp));
ThiscodeworksequallywellinsideofadoGet()method.
SeeAlso
Recipe18.5onautomaticallyrefreshingaJSP;Recipe18.1andRecipe18.2onexaminingrequestheadersinaservletandaJSP;Recipe18.3onusingafiltertowraptherequestandforwarditalongthefilterchain;Recipe18.6onusingalistenertotrackrequests.
Recipe18.5AutomaticallyRefreshingaJSP
Problem
YouwanttorefreshaJSPrequestataspecifiedinterval.
Solution
UseaJSPscriptletthataddsaRefreshresponseheadertotheresponse.
Discussion
ThefollowingscriptletcodeaddsaRefreshheaderthatspecifiesa60-secondintervalforrefreshingtheJSP.PlacethiscodeatthetopoftheJSPbeforeanycontentappears:
<%response.addHeader("Refresh","60");%>
IfyouwanttorefreshtheJSPtoanotherwebcomponentorpage,usethissyntax:
<%response.addHeader("Refresh","10;
http://localhost:8080/home/thanks.jsp");%>
SeeAlso
Example18-6inRecipe18.4onrefreshingaservlet;Example18-7inRecipe18.4onlimitingthenumberofautomaticrefreshesofaservlet;Recipe18.1andRecipe18.2onexaminingrequestheadersinaservlet
andaJSP,respectively;Recipe18.3onusingafiltertowraptherequestandforwarditalongthefilterchain;Recipe18.6onusingalistenertotrackrequests.
Recipe18.6CountingtheNumberofWebApplicationRequests
Problem
Youwanttocountthenumberofrequestshandledbyawebapplication.
Solution
Useajavax.servlet.ServletRequestListenertobenotifiedwheneveranHTTPrequestisinitialized.
Discussion
Arequestlistenerisagoodcandidatefortrackingrequests,becausethewebcontainernotifiesthelistenerofnewrequestsbycallingitsrequestInitialized()method.Example18-8keepstrackoftherequestcountwithastaticclassvariablenamedreqCount.TheprogramincrementsthisvariableinasynchronizedblockwithintherequestInitialized()method.
TheServletContextisusedtologamessageabouttherequestsothatyoucanobservethelistenerbehavior.However,abusyproductionapplicationthatlogsinformationabouteveryrequesttypicallyrepresentsaninefficientuseofwebcontainerresources.Thistypeofloggingactivityshouldbereservedfordevelopmentapplications.
Example18-8.Arequestlistenerclassforcountingapplicationrequests
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassReqListenerimplementsServletRequestListener{
privatestaticlongreqCount;
publicvoidrequestInitialized(ServletRequestEventsre){
//usedforloggingpurposes
ServletContextcontext=sre.getServletContext();
//Usedtogetinformationaboutanewrequest
ServletRequestrequest=sre.getServletRequest();
//ThestaticclassvariablereqCountisincrementedinthisblock;
//theincrementingofthevariableissynchronizedsothatone
//threadisnotreadingthevariablewhileanotherincrementsit
synchronized(context){
context.log(
"Requestfor"+
(requestinstanceofHttpServletRequest?
((HttpServletRequest)request).getRequestURI():
"Unknown")+";Count="+++reqCount);
}//synchronized
}
publicvoidrequestDestroyed(ServletRequestEventsre){
//Calledwhentheservletrequestisgoingooutofscope.
}//requestDestroyed
}
YoucanaccessthenewServletRequestinthetwoServletRequestListenermethodsbycallingServletRequestEvent.getServletRequest().YoumustcasttheServletRequestreturnvaluetoanHttpServletRequesttocallthelatterclass'smethods.Example18-8accessesthenewHttpServletRequestsinordertocallthoseobject'sgetRequestURI()method,whichprovidespartoftheinformationthecodeincludesinaloggingmessage.
YoumustregistertheServletRequestListenerinweb.xml:
<listener>
<listener-class>com.jspservletcookbook.ReqListener</listener-class>
</listener>
Thewebcontainerthencreatesaninstanceofthelistenerwhenitstartsup.Hereisanexampleofaserver-logentrywhenarequestismadetotheapplicationwithinwhichtherequestlistenerisregistered:
2003-05-3007:22:21Requestfor/home/servlet/com.jspservletcookbook.SessionDisplay;
Count=2
ForTomcat,thislinewouldbedisplayedinthelogfilefoundin<Tomcat-installation-directory>/logs.
SeeAlso
Recipe18.1andRecipe18.2onexaminingrequestheadersinaservletandaJSP;Recipe18.3onusingafiltertowraptherequestandforwarditalongthefilterchain;Chapter7onhandlingrequestparametersandJavaBeanpropertieswithservlets,JSPs,andfilters.
Chapter19.FilteringRequestsandResponses
Introduction
Recipe19.1.MappingaFiltertoaServlet
Recipe19.2.MappingaFiltertoaJSP
Recipe19.3.MappingMoreThanOneFiltertoaServlet
Recipe19.4.ChangingtheOrderinWhichFiltersareAppliedtoServlets
Recipe19.5.ConfiguringInitializationParametersforaFilter
Recipe19.6.OptionallyBlockingaRequestwithaFilter
Recipe19.7.FilteringtheHTTPResponse
Recipe19.8.UsingFilterswithRequestDispatcherObjects
Recipe19.9.CheckingFormParameterswithaFilter
Recipe19.10.BlockingIPAddresseswithaFilter
Introduction
ServletfilteringwasintroducedwiththeservletAPIv2.3in2001.Filteringisapowerfultechnologyforservletdevelopers,whocanuseittogeneratechainsofJavaclassesthatexecuteinsequenceinresponsetoclientrequests.
DevelopersbeginbycreatingoneormoreJavaclassesthatimplementthejavax.servlet.Filterinterface.Theseclassescanundertakeanumberofactionspriortoaservlet'srequesthandling,creatingachainofactionsbeforetherequestisdeliveredtoitsdestination(includingblockingtherequestaltogether).Theseactionsinclude,accordingtotheFilterAPIdocumentation:
Authenticationofrequests
Dataencryption
Datacompression
Logging
ExtensibleStylesheetLanguageTransformation(XSLT)filtering
Imageconversion
AccesstheJavadocfortheFilterinterfaceat:http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/Filter.html.
Registerafilterinthedeploymentdescriptor,andthenmapthe
registeredfiltertoeitherservletnamesorURLpatternsinyourapplication'sdeploymentdescriptor.Whenthewebcontainerstartsupyourwebapplication,itcreatesaninstanceofeachfilterthatyouhavedeclaredinthedeploymentdescriptor.Thefiltersexecuteintheorderthattheyaredeclaredinthedeploymentdescriptor.
Recipe19.1MappingaFiltertoaServlet
Problem
Youwanttomaporapplyafiltertoanindividualservlet.
Solution
Usethefilterandfilter-mappingelementsinweb.xmltoassociatethefilterwiththeservlet.
Discussion
Thewebcontainerfindsoutaboutthefiltersthatyouwanttoapplytoaservletbyusinginformationinthedeploymentdescriptor.ThefilterelementassociatesafilternamewithaJavaclassthatimplementsthejavax.servlet.Filterinterface.Thefilter-mappingelementthenassociatesindividualfilterswithURLmappingsorpaths,similartotheservlet-mappingelementthatyouhaveprobablyusedbeforeinweb.xml.Example19-1showsadeploymentdescriptorfromtheservletAPIv2.3thatincludesthemappingofafilternamedLogFiltertotheservletpath/requestheaders.
Example19-1.Mappingafiltertoaservlet
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-application_2_3.dtd"
>
<web-app>
<!--registerthefilter-->
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.jspservletcookbook.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/requestheaders</url-pattern>
</filter-mapping>
<!--registertheservlettowhichthefilterismapped-->
<servlet>
<servlet-name>requestheaders</servlet-name>
<servlet-class>com.jspservletcookbook.RequestHeaderView</servlet-class>
</servlet>
<!--HereistheURLmappingfortherequestheadersservlet-->
<servlet-mapping>
<servlet-name>requestheaders</servlet-name>
<url-pattern>/requestheaders</url-pattern>
</servlet-mapping>
</web-app>
Whenaclientsendsarequesttotheservletpath/requestheaders,thewebcontainerappliestheLogFilterfiltertotherequest.Thisservletpath,asin:
http://localhost:8080/home/requestheaders
istheonlyservletpathtowhichthisfilterisapplied.Asyoumighthaveguessed,theLogFilterlogssomeinformationabouttherequestbeforetherequestcontinuesalongtoitsservletdestination.Example19-2showsthefilterclassfortheLogFilterinExample19-1.
Thisfilterclassprovidestheadditionalbenefitofshowingyouhowtologamessageinsideofafilter!
Makesureto:
Createthefilterwithaconstructorthatdoesnottakeanyparameters
Givethefilterclassapackagename
StorethefilterintheWEB-INF/classesdirectoryofthewebapplication,includingitspackage-relateddirectories
Mapthefiltertotheservletinweb.xml,asinExample19-1
Example19-2.Afilterthatlogssomeinformation
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
importorg.apache.log4j.Logger;
importorg.apache.log4j.PropertyConfigurator;
publicclassLogFilterimplementsFilter{
privateFilterConfigconfig;
privateLoggerlog;
//CreatesnewLogFilter
publicLogFilter(){}
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
this.config=filterConfig;
//loadtheconfigurationforthisapplication'sloggersusingthe
//servletLog.propertiesfile
PropertyConfigurator.configure(config.getServletContext().
getRealPath("/")+
"WEB-INF/classes/servletLog.properties");
log=Logger.getLogger(LogFilter.class);
log.info("Loggerinstantiatedin"+getClass().getName());
}//init
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsjava.io.IOException,ServletException{
HttpServletRequestreq=null;
if(log!=null&&(requestinstanceofHttpServletRequest)){
req=(HttpServletRequest)request;
log.info(
"Requestreceivedfrom:"+req.getRemoteHost()+"for:"+
req.getRequestURL());}
//passrequestbackdownthefilterchain
chain.doFilter(request,response);
}//doFilter
publicvoiddestroy(){
/*calledbeforetheFilterinstanceisremoved
fromservicebythewebcontainer*/
log=null;
}
}
ThisfilterlogstheremotehostoftheclientrequestandtheURLthattheclientrequested.Hereisanexampleoftheloggedinformation:
INFO-Requestreceivedfrom:localhostfor:http://localhost:8080/home/requestheaders
Thefilterusesthelog4jlibrary(seeChapter14)fromtheApacheSoftwareFoundation.
Sincethefirstparametertothefilter'sdofilter()methodisajavax.servlet.ServletRequesttype,thisparametermustbecasttoanHttpServletRequesttocallmethodssuchasHttpServletRequest.getRemoteHost().
SeeAlso
Recipe7.9onusingafiltertoreadrequestparametervalues;Recipe11.11onusingafiltertomonitorsessionattributes;Recipe18.3onusingafiltertoaltertherequest;Recipe19.2-Recipe19.4onmappingfilterstowebcomponents;Recipe19.5onconfiguringfilterinitializationparameters;Recipe19.6onblockingrequests;Recipe19.7onfilteringtheHttpServletResponse;Recipe19.8onusingfilterswithRequestDispatchers;Recipe19.9onusingfilterstocheckrequestparameters;Recipe19.10onusingfilterstodisallowrequestsfromcertainIPaddresses.
Recipe19.2MappingaFiltertoaJSP
Problem
YouwanttohavethewebcontainerapplyafiltertorequestsforacertainJSPpage.
Solution
Usetheurl-patternchildelementofthefilter-mappingelementinthedeploymentdescriptortomapthefiltertotheJSP.
Discussion
MapafiltertoaJSPbyspecifyingthepathtotheJSPpageusingthefilter-mappingelement'surl-patternsubelement.Example19-3showsaweb.xmlconfigurationthatmapsthefilterinExample19-2totherequestHeaders.jsp.
Example19-3.MappingafiltertoaJSP
<!--topofweb.xmldeploymentdescriptor-->
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.jspservletcookbook.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/displayHeaders.jsp</url-pattern>
</filter-mapping>
<!--restofdeploymentdescriptor-->
Youcancreateanumberoffiltermappingsforasinglefilter,eachwiththeirowntypeofURLpattern.
WiththeconfigurationofExample19-3,anyrequestsfor/displayHeaders.jspwillpassthroughthefilternamedLogFilter.Example19-2showsthesourcecodefortheLogFilterclass.Thecodelogsamessageabouttherequest,beforetherequestispassedalongthefilterchaintotheJSP.Theloggedmessagelookslike:
INFO-Requestreceivedfrom:localhostfor:http://localhost:8080/home/
displayHeaders.jsp
TheJSPitselfdoesnothavetobeconfiguredinaspecialwayforthefiltertobeappliedtoit.YoucanapplythefiltertoallJSPswiththisconfiguration:
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
TheURLpattern*.jspisanextensionmappingthatassociatestheLogFilterwithanyofthewebapplication'scomponentsthatendwith.jsp.
SeeAlso
Recipe7.9onusingafiltertoreadrequestparametervalues;Recipe11.11onusingafiltertomonitorsessionattributes;Recipe18.3onusingafiltertoalterthenforwardtherequest;Recipe19.3onmappingmorethanonefiltertoaservlet;Recipe19.4onchangingtheorderfiltersareappliedtoaservlet;Recipe19.5onconfiguringfilterinitializationparameters;Recipe19.6onblockingrequests;Recipe19.7onfilteringtheHttpServletResponse;Recipe19.8onusingfilterswithRequestDispatchers;Recipe19.9onusingfilterstocheckrequestparameters;Recipe19.10onusingfilterstodisallowrequestsfromcertainIPaddresses.
Recipe19.3MappingMoreThanOneFiltertoaServlet
Problem
YouwantrequestsforaservletorJSPtopassthroughmorethanonefilter.
Solution
MapeachfiltertotheservletorJSPusingfilter-mappingelementsinthedeploymentdescriptor.Thefiltersareappliedtotheservletintheordertheyappearinthedeploymentdescriptor.
Discussion
Yourwebapplicationmaydefineseveraldifferentfilterswithaspecificpurpose.Forinstance,onefiltermightlogmessages,whileanotherfilterauthenticatesusers.Itisstraightforwardtocreateafilterchainthatapplieseachfilterinaspecifiedordertoaservlet.Youusethefilter-mappingelementtomapeachfiltertothetargetservlet(orJSP).Thewebcontainerthenappliesthefilterstothetargetintheorderthatthefilter-mappingelementsaredefinedinthedeploymentdescriptor.
Example19-4configurestwofilters:AuthenFilterandLogFilter.Thefilter-mappingelementsforthesefiltersthenmaptheservletnamerequestheaderstoeachofthesefilters.Theorderofthefilter-mappingelementsinExample19-4specifiesthattheauthenticationfilter(AuthenFilter)mustbeappliedtotheservletnamedrequestheadersfirst,followedbytheLogFilter.
Tomapafiltertoaservletname,theservlethastoberegisteredinweb.xml.Example19-4registerstherequestheadersservletbeneaththefilterandfilter-mappingelements.
Example19-4.Mappingmorethanonefiltertoaservlet
<!--topofweb.xmldeploymentdescriptor-->
<filter>
<filter-name>AuthenFilter</filter-name>
<filter-class>com.jspservletcookbook.AuthenticateFilter</filter-class>
</filter>
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.jspservletcookbook.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthenFilter</filter-name>
<servlet-name>requestheaders</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<servlet-name>requestheaders</servlet-name>
</filter-mapping>
<!--servletdefinitions-->
<servlet>
<servlet-name>requestheaders</servlet-name>
<servlet-class>com.jspservletcookbook.RequestHeaderView</servlet-class>
</servlet>
<!--servlet-mappingsectionofweb.xml-->
<servlet-mapping>
<servlet-name>requestheaders</servlet-name>
<url-pattern>/requestheaders</url-pattern>
</servlet-mapping>
<!--restofdeploymentdescriptor-->
Whenauserrequeststherequestheadersservletusingtheservletpath/requestheaders,asspecifiedintheservlet-mappingelement,therequestpassesthroughtheAuthenFilterandLogFilterbeforeitreachesitsservletdestination.
Thesameprocessappliestoafilter-mappingthatusesaurl-patternelementinsteadofaservlet-nameelement.Theorderofthefilter-mappingelementsinthedeploymentdescriptordeterminestheorderofthefiltersappliedtothewebcomponentsthatmatchtheurl-pattern.
SeeAlso
Recipe7.9onusingafiltertoreadrequestparametervalues;Recipe11.11onusingafiltertomonitorsessionattributes;Recipe18.3onusingafiltertoalterthenforwardtherequest;Recipe19.4onchangingtheorderfiltersareappliedtoaservlet;Recipe19.5onconfiguringfilterinitparameters;Recipe19.6onblockingrequests;Recipe19.7onfilteringtheHttpServletResponse;Recipe19.8onusingfilterswithRequestDispatchers;Recipe19.9onusingfilterstocheckrequestparameters;Recipe19.10onusingfilterstodisallowrequestsfromcertainIPaddresses.
Recipe19.4ChangingtheOrderinWhichFiltersareAppliedtoServlets
Problem
Youwanttochangetheorderinwhichfiltersareappliedtowebcomponents.
Solution
Changetheorderoffilter-mappingelementsinthedeploymentdescriptor.
Discussion
Theorderoffilter-mappingelementsinweb.xmldeterminestheorderinwhichthewebcontainerappliesthefiltertotheservlet.Example19-5reversestheorderofthefilter-mappingelementsthatmaptwofilterstotheservletnamedrequestheaders,comparedwithRecipe19.3.TheLogFilteristhusappliedtotheservletbeforetheAuthenFilter.Anyrequestsfortheservletpassthroughachain:LogFilter AuthenFilter requestheadersservlet.
Example19-5.Reversingtheorderoffilter-mappingelements
<!--LogFilterappliestotherequestheadersservlet
beforeAuthenFilter-->
<filter-mapping>
<filter-name>LogFilter</filter-name>
<servlet-name>requestheaders</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>AuthenFilter</filter-name>
<servlet-name>requestheaders</servlet-name>
</filter-mapping>
SeeAlso
Recipe7.9onusingafiltertoreadrequestparametervalues;Recipe11.11onusingafiltertomonitorsessionattributes;Recipe18.3onusingafiltertoalterthenforwardtherequest;Recipe19.1-Recipe19.3onmappingfilterstowebcomponents;Recipe19.5onconfiguringfilterinitparameters;Recipe19.6onblockingrequests;Recipe19.7onfilteringtheHttpServletResponse;Recipe19.8onusingfilterswithRequestDispatchers;Recipe19.9onusingfilterstocheckrequestparameters;Recipe19.10onusingfilterstodisallowrequestsfromcertainIPaddresses.
Recipe19.5ConfiguringInitializationParametersforaFilter
Problem
Youwanttomakeaninitialization(init)parameteravailabletoafilter.
Solution
Usetheinit-paramchildelementofthefilterelementtodeclaretheinitializationparameteranditsvalue.Insidethefilter,accesstheinitparameterbycallingtheFilerConfigobject'sgetInitParametermethod.
Discussion
Example19-6showsafilterdeclaredinthedeploymentdescriptor.Thefilterincludesaninitparameternamedlog-id.
Example19-6.Afilterdeclaredinthedeploymentdescriptorwithaninitparameter
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.jspservletcookbook.LogFilter</filter-class>
<init-param>
<param-name>log-id</param-name>
<param-value>A102003</param-value>
</init-param>
</filter>
Example19-7showsthecodeyouwoulduseinsidethefiltertoaccesstheinitparameteranditsvalue.ThecodeinitializestheFilterConfigobjectinitsinitmethod,whichiscalledoncewhenthewebcontainercreatesaninstanceofthefilter.Thecodethengetsthevalueofthefilter'sinitparameterbycalling:
Stringid=config.getInitParameter("log-id");
MakesurethatthecodecheckswhetherthereturnvaluefromgetInitParameterisnullbeforethecodedoessomethingwiththatobject.
Example19-7.Accessinganinitparamvalueinafilter
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
importorg.apache.log4j.Logger;
importorg.apache.log4j.PropertyConfigurator;
publicclassLogFilterimplementsFilter{
privateFilterConfigconfig;
privateLoggerlog;
//CreatesnewLogFilter
publicLogFilter(){}
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
this.config=filterConfig;
//loadtheconfigurationforthisapplication'sloggers
//usingtheservletLog.propertiesfile
PropertyConfigurator.configure(config.getServletContext().
getRealPath("/")+
"WEB-INF/classes/servletLog.properties");
log=Logger.getLogger(LogFilter.class);
log.info("Loggerinstantiatedin"+getClass().getName());
}
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsjava.io.IOException,ServletException{
HttpServletRequestreq=null;
Stringid=config.getInitParameter("log-id");
if(id==null)
id="unknown";
if(log!=null&&(requestinstanceofHttpServletRequest)){
req=(HttpServletRequest)request;
log.info("Logid:"+id+":Requestreceivedfrom:"+
req.getRemoteHost()+"for"+req.getRequestURL());}
chain.doFilter(request,response);
}//doFilter
publicvoiddestroy(){
/*calledbeforetheFilterinstanceisremoved
fromservicebythewebcontainer*/
log=null;
}
}
Hereishowthelogoutputappears:
INFO-Logid:A102003:Requestreceivedfrom:localhostforhttp://localhost:8080/
home/requestheaders
YoucanalsousetheFilterConfigobject'sgetInitParameterNamesmethodtogetalloftheinitparameternamesinajava.util.Enumerationobject.
SeeAlso
Recipe7.9onusingafiltertoreadrequestparametervalues;Recipe11.11onusingafiltertomonitorsessionattributes;Recipe18.3onusingafiltertoalterthenforwardtherequest;Recipe19.1-Recipe19.4onmappingfilterstowebcomponents;Recipe19.6onblockingarequest;Recipe19.7onfilteringtheHttpServletResponse;Recipe19.8onusingfilterswithRequestDispatchers;Recipe19.9onusingfilterstocheckrequestparameters;Recipe19.10onusingfilterstodisallowrequestsfromcertainIPaddresses.
Recipe19.6OptionallyBlockingaRequestwithaFilter
Problem
Youwanttheoptiontoblockarequestwithafilter.
Solution
DonotcalltheFilterChainobject'sdoFilter()methodinsideofthefilter.Outputtheresponsetotheclientinsideofthefilter'sdoFilter()methodinstead.
Discussion
Afilterblocksarequestfromgettingtoawebcomponent,suchasaservlet,JSP,orHTMLpage,bynevercallingFilterChain.doFilter()insidethefilter'sowndoFilter()method.
TheBlockFilterclassinExample19-8attemptstoauthenticatetheuserbasedonarequestparameter.Iftheauthenticationfails,thefilterusestheresponseobjecttooutputaresponsetotheclient,andtherequestiseffectivelyblockedfromreachingtherequestedservlet.Afiltercanoutputthefinalresponsetotheclient,notjustinitiateitsfilteringtasks.
Example19-8.Afilteroptionallyblockstherequestandissuesaresponseitself
packagecom.jspservletcookbook;
importjava.io.PrintWriter;
importjava.io.IOException;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassBlockFilterimplementsFilter{
privateFilterConfigconfig;
/**CreatesnewBlockFilter*/
publicBlockFilter(){}
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
this.config=filterConfig;
}
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsIOException,ServletException{
HttpServletRequestreq=null;
booleanauthenticated=false;
PrintWriterout=null;
if(requestinstanceofHttpServletRequest){
req=(HttpServletRequest)request;
Stringuser=req.getParameter("user");//gettheusername
authenticated=authenticateUser(user);//authenticatetheuser
}
if(authenticated){
//theyareauthenticated,sopassalongtherequest
chain.doFilter(request,response);
else{
//havethefiltersendbacktheresponse
response.setContentType("text/html");
out=response.getWriter();
out.println(
"<html><head><title>AuthenticationResponse</title>");
out.println("</head><body>");
out.println("<h2>Sorryyourauthenticationattemptfailed</h2>");
out.println("</body></html>");
}
}//doFilter
publicvoiddestroy(){
/*calledbeforetheFilterinstanceisremoved
fromservicebythewebcontainer*/
}
privatebooleanauthenticateUser(StringuserName){
//authenticatetheuserusingJNDIandadatabase,forinstance
//returnfalsefordemonstrationpurposes
returnfalse;
}//authenticateUser
}
Thecodeauthenticatestheuserbygettingthehypotheticalusernameas
arequestparameter.Thenameistheparameterforthefilter'sauthenticateUser()method,whichreturnsfalsetodemonstratethefilter'sresponsetotheclient.ThefilterusesthePrintWriterfromthejavax.servlet.ServletResponseobject,whichisaparametertothedoFilter()method.ThePrintWritersendsHTMLbacktotheclient.Figure19-1showstheresponseoutputinawebbrowser.
Figure19-1.TheHTMLpagereturnedbyablockingfilter
Ifyouregularlyusefilterstosendresponsestoaclient,considercreatingaJavaBeantocustomizetheresponse.StorethebeanclassinitspackagebeneathWEB-INF/classes,andusethebeaninsidethefilter.
SeeAlso
Recipe7.9onusingafiltertoreadrequestparametervalues;Recipe11.11onusingafiltertomonitorsessionattributes;Recipe18.3onusingafiltertoalterthenforwardtherequest;Recipe19.1-Recipe19.4onmappingfilterstowebcomponents;Recipe19.5onconfiguringinitparametersforafilter;Recipe19.7onfilteringtheHTTPresponse;Recipe19.8onusingfilterswithRequestDispatchers;Recipe19.9on
usingfilterstocheckrequestparameters;Recipe19.10onusingfilterstodisallowrequestsfromcertainIPaddresses.
Recipe19.7FilteringtheHTTPResponse
Problem
Youwanttochangetheresponsewithafilterwhiletheclientrequestisenroutetotheservlet.
Solution
Changethejavax.servlet.ServletResponseinsidethefilter'sdoFilter()methodbywrappingtheresponsewithyourownobject.ThenpassthewrappedresponseasaparameterintotheFilterChain.doFilter()method.
Discussion
Herearethestepsforchangingaresponsewithafilterandawrapperclass:
1. CreateaJavaclassthatextendsjavax.servlet.http.HttpServletResponseWrapper.
Placethisclass,includingitspackage-relateddirectories,inWEB-INF/classes.
Usethewrapperclassinthefiltertowraptheresponseobject,whichisaparametertothefilter'sdoFilter()method.
Callthechain.doFilter()methodwiththewrappedresponseasaparameter.
Example19-9showstheJavaclassthatwewillusetowraptheresponseobject.
Ifyouarejustmakingasimpleresponsechange,youdonothavetogotothetroubleofusinganHttpServletResponseWrapperclass.Thiscodeinsideofafilter'smethodaddsaheadertotheresponse,thencallsthechain.doFilter()methodwiththealteredresponse:
if(responseinstanceofHttpServletResponse){
//casttoHttpServletResponsetocall
//addHeader
myHttpResponse=
((HttpServletResponse)response);
myHttpResponse.addHeader("WWW-Authenticate",
"BASICrealm=\"Admin\"");
chain.doFilter(request,response);}
TheResponseWrapperclasscontainstheskeletonofanewmethodnamedgetWebResource.Iwanttoshowthemechanicsofwrappingtheresponseinafilter,sohavekeptthiswrapperclassverysimple.
AlltheotherHttpServletResponse-derivedmethodcallsaredelegatedtothewrappedresponseobject,whichistheconvenienceofextendingHttpServletResponseWrapper.
Example19-9.AnHttpServletResponseWrapperclassforuseinafilter
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.HttpServletResponseWrapper;
importjavax.servlet.http.HttpServletResponse;
publicclassResponseWrapperextendsHttpServletResponseWrapper{
publicResponseWrapper(HttpServletResponseresponse){
super(response);
}
publicStringgetWebResource(StringresourceName){
//ImplementamethodtoreturnaStringrepresenting
//theoutputofawebresource
//SeeRecipe13.5
return"resource";//forthecompiler...
}//getWebResource
}
Example19-10showsthedoFilter()methodinsidethefilterthatusesthisResponseWrapperclass.
TheclassextendingHttpServletResponseWrappermustbeplacedbeneathWEB-INF/classes,withadirectorystructurethatmatchesitspackagename.
Example19-10.ThedoFilter()methodofafilterthatusesaHttpServletResponseWrapperclass
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsjava.io.IOException,ServletException{
if(responseinstanceofHttpServletResponse){
chain.doFilter(request,
newResponseWrapper((HttpServletResponse)response));
}else{
chain.doFilter(request,response);
}
}//doFilter
Thecodecallsthechain.doFilter()methodandpassesinthewrappedresponseasaparameter.Thewebresourceattheendofthechainhasaccesstothecustomizedresponseobjectandcancalltheadditionalmethodtheresponsewrapperclasshasdefined.AlltheothermethodcallsontheHttpServletResponseobject,suchasgetWriter()orgetOutputStream(),arepassedthroughtothewrappedresponseobject.
SeeAlso
Recipe7.9onusingafiltertoreadrequestparametervalues;Recipe11.11onusingafiltertomonitorsessionattributes;Recipe18.3onusingafiltertoaltertherequest;Recipe19.1-Recipe19.4onmappingfilterstowebcomponents;Recipe19.5onconfiguringinitparametersforafilter;Recipe19.6onblockingarequest;Recipe19.8onusingfilterswithRequestDispatchers;Recipe19.9onusingfilterstocheckrequestparameters;Recipe19.10onusingfilterstodisallowrequestsfromcertainIPaddresses.
Recipe19.8UsingFilterswithRequestDispatcherObjects
Problem
Youwanttoapplyafiltertoaservletwhoseoutputisincludedinanotherservlet.
Solution
Usethejavax.servlet.RequestDispatcherobjecttoincludetheservlet'soutput.Configurethefilterinweb.xmlwithadispatcherelementcontainingthecontent"INCLUDE"(servletAPIv2.4andaboveonly!).
Discussion
TheservletAPIv2.4introducedanewtwistforworkingwithRequestDispatchers.Usingthefilter-mappingelementinthedeploymentdescriptor,youcanspecifythatthefilterappliestoaservletthatispartofaRequestDispatcherincludeorforwardaction.
Example19-11showsaweb.xmlconfigurationforafilter.
Example19-11.ApplyingafiltertoaservletusingaRequestDispatcher
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<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_2_4.xsd"version="2.4">
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.jspservletcookbook.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/requestheaders</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
ThedispatcherelementsintheexampleconfigurationspecifythattheLogFilterappliestorequestsfortheservletpath/requestheaders,aswellastoanyRequestDispatchersthatincludetheoutputoftheservletpath/requestheaders.
Similarly,ifyouwanttoinitiateafilterwhenyouareusingaRequestDispatchertoforwardarequesttoanothercomponent,usetheFORWARDvaluewiththedispatcherelement,asin:
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/requestheaders</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Example19-12showsaservlet'sdoGetmethodthatcreatesaRequestDispatcherspecifyingthepath/requestheaders.Thiscodeincludestheservletoutputrepresentedbythatpath.BecauseofExample19-11sconfigurationinweb.xml,however,thewebcontainerappliesthe
LogFilterbeforetheservletmappedtothe/requestheaderspathisexecuted.
Example19-12.Aservletincludesanotherservlet'soutput,triggeringafilter
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
/*Theoutputoftheservletatpath"/requestheaders"will
beincludedinthisservlet'soutput,butfirsttherequest
willpassthroughtheLogFilterbeforeitissenttothe
"/requestheaders"servlet*/
RequestDispatcherdispatch=request.getRequestDispatcher(
"/requestheaders");
dispatch.include(request,response);
}
Figure19-2illustratestheprocessoffiltersandRequestDispatchers.
Figure19-2.Alogfilterintervenesbetweenaservlet,includinganotherservlet'soutput
InFigure19-2,awebclientrequeststheservletatpath/home/servlet1,with/homerepresentingthecontextpath.Theservlet1componentusesaRequestDispatchertoincludetheoutputofservlet2.Basedonafilter-mappingelementinweb.xml,anyrequestsforservlet2involvingaRequestDispatcherincludeactionmustfirstpassthroughthelogfilter.Thisfilterisconfiguredwithafilterelementinweb.xmlwiththename"LogFilter"(Figure19-2doesnotshowthisconfiguration;seeExample19-11).
ThistypeofRequestDispatcherset-upisonlysupportedbyServletAPIv2.4andabove.
SeeAlso
Chapter6onincludingcontentusingRequestDispatchers;Recipe7.9onusingafiltertoreadrequestparametervalues;Recipe11.11onusingafiltertomonitorsessionattributes;Recipe18.3onusingafiltertoalterthenforwardtherequest;Recipe19.1-Recipe19.4onmappingfilterstowebcomponents;Recipe19.5onconfiguringinitparametersforafilter;Recipe19.6onblockingarequest;Recipe19.7onfilteringtheHTTPresponse;Recipe19.9onusingfilterstocheckrequest
parameters;Recipe19.10onusingfilterstodisallowrequestsfromcertainIPaddresses.
Recipe19.9CheckingFormParameterswithaFilter
Problem
Youwanttouseafiltertocheckthevaluesthatauserhasenteredintoaform.
Solution
UsethedeploymentdescriptortomapthefiltertotheservletorJSPthatisthetargetoftheform.
Discussion
FiltersofferanalternativetoJavaScriptandotherserver-sidelanguagesforcheckingwhethertheuserhasenteredvalidvaluesintoHTMLformfields.ThefilterinthisrecipeinitiatesabasiccheckoftherequestparameterstodetermineiftheyarenullortheemptyString.
Example19-13isaJSPthatcontainsanHTMLform.TheJSPincludessomeembeddedJSTLtagsthatfillinthetextfieldswithanycorrectvaluesiftheformisreturnedtotheuserforcorrections.Inmostcases,auserfillsinthevastmajorityofthefieldscorrectly,butmightmakeamistakeinoneortwoofthem.Youdonotwanttomakehimfilloutallofthefieldsagain.
Example19-13.AJSPcontainingaformforuserstofillout
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.0Transitional//EN">
<html>
<head>
<title>PersonalInformation</title>
</head>
<bodybgcolor="#ffffff">
<c:iftest="${!(emptyerrorMsg)}">
<fontcolor="red"><c:outvalue="${errorMsg}"/></font>
</c:if>
<h2>Pleaseenteryournameandemailaddress</h2>
<table>
<formaction="/home/thanks.jsp">
<tr><tdvalign="top">Firstname:</td>
<tdvalign="top">
<inputtype="text"name="first"size="15"value=
'<c:outvalue="${first}"/>'>
</td>
<tdvalign="top">Middleinitial:</td>
<tdvalign="top">
<inputtype="text"name="middle"size="2"value=
'<c:outvalue="${middle}"/>'>
</td>
</tr>
<tr>
<tdvalign="top">Lastname:</td>
<tdvalign="top">
<inputtype="text"name="last"size="20"value=
'<c:outvalue="${last}"/>'>
</td></tr>
<tr>
<tdvalign="top">Youremail:</td>
<tdvalign="top">
<inputtype="text"name="email"size="20"value=
'<c:outvalue="${email}"/>'>
</td></tr>
<tr><tdvalign="top"><inputtype="submit"value="Submit"></td>
<td></td></tr>
</form>
</table>
</body>
</html>
WhentheusersubmitsExample19-13,thebrowsersendstheforminformationtotheURLspecifiedintheformtag'sactionattribute:aJSPpagenamedthanks.jsp.ThedeploymentdescriptormapsthefilterinExample19-14totheURLthanks.jsp.Thefilterisdesignedtocheckthefields'valuestodetermineiftheuserleftanyofthemblankand,ifso,returntheusertotheform(namedform.jsp).
Makesuretodevelopallfilterswithaconstructorthatdoesnottakeanyarguments.
Example19-14.Thefilterthatchecksparametersvalues
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.util.Enumeration;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassCheckFilterimplementsFilter{
privateFilterConfigconfig;
publicCheckFilter(){}
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
this.config=filterConfig;
}
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsIOException,ServletException{
//Getalltheparameternamesassociatedwiththeformfields
Enumerationparams=request.getParameterNames();
booleanrejected=false;
//Cyclethrougheachoneoftheparameters;ifanyofthem
//areempty,callthe'reject'method
while(params.hasMoreElements()){
if(isEmpty(request.getParameter((String)params.
nextElement()))){
rejected=true;
reject(request,response);
}//if
}//while
//Passtherequesttoitsintendeddestination,ifeverything
//isokay
if(!rejected)
chain.doFilter(request,response);
}//doFilter
privatebooleanisEmpty(Stringparam){
if(param==null||param.length()<1){
returntrue;
}
returnfalse;
}
privatevoidreject(ServletRequestrequest,ServletResponseresponse)
throwsIOException,ServletException{
//Createanerrormessage;storeitinarequestattribute
request.setAttribute("errorMsg",
"Pleasemakesuretoprovideavalidvalueforallofthetext"+
"fields.");
Enumerationparams=request.getParameterNames();
StringparamN=null;
//Createrequestattributesthattheform-relatedJSPwill
//usetofillintheformfieldsthathavealreadybeen
//filledoutcorrectly.Thentheuserdoesnothavetofill
//intheentireformalloveragain.
while(params.hasMoreElements()){
paramN=(String)params.nextElement();
request.setAttribute(
paramN,request.getParameter(paramN));
}
//UseaRequestDispatchertoreturntheusertotheformin
//ordertofillinthemissingvalues
RequestDispatcherdispatcher=request.
getRequestDispatcher("/form.jsp");
dispatcher.forward(request,response);
}//reject
publicvoiddestroy(){
/*calledbeforetheFilterinstanceisremoved
fromservicebythewebcontainer*/
}
}
TheJavacommentsinExample19-14explainwhatisgoingoninthisfilter.Basically,theuserisreturnedtotheform,whichdisplaysanerrormessageifanyoftherequestparametersareempty.Example19-15showshowtheCheckFilterismappedinweb.xml.Iftheuserfillsintheformcorrectly,hisrequestissenttothethanks.jsppagewithoutinteruptionbythefilter.
Example19-15.TheCheckFilterisregisteredandmappedinweb.xml
<!--startofweb.xml...-->
<filter>
<filter-name>CheckFilter</filter-name>
<filter-class>com.jspservletcookbook.CheckFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CheckFilter</filter-name>
<url-pattern>/thanks.jsp</url-pattern>
</filter-mapping>
<!--restofweb.xml...-->
Figure19-3showsanHTMLformthatwaspartiallyfilledoutandsubmitted.Thefiltersenttheformbacktotheuserwithamessage(inaredfont).
Figure19-3.AfilterforwardsanerrormessagetoaJSP
SeeAlso
Chapter6onincludingcontentusingRequestDispatchers;Recipe19.8onusingfilterswithRequestDispatchers;Recipe7.9onusingafiltertoreadrequestparametervalues;Recipe18.3onusingafiltertoalterthenforwardtherequest;Recipe19.1-Recipe19.4onmappingfilterstowebcomponents;Recipe19.5onconfiguringinitparametersforafilter;Recipe19.6onblockingarequest;Recipe19.7onfilteringtheHTTPresponse.
Recipe19.10BlockingIPAddresseswithaFilter
Problem
YouwanttouseafilterthatcheckstheIPaddressassociatedwiththerequest.
Solution
UseafilterthatcallstheHttpServletRequest'sgetRemoteAddr()methodinsidethedoFilter()methodandblockstherequestbynotcallingchain.doFilter().
Discussion
Atypicaluseofafilterinawebapplicationistochecktherequesttomakesureit'sacceptable.Let'ssayyoursecuritydivisionhasdiscoveredthatacertainrangeofIPaddressesrepresentnastyclientsyouwanttorebuffthosefolkswitha"403Forbidden"HTTPresponse.
Example19-16blocksanyclientIPaddressbeginningwith"192.168."
Example19-16.AfilterforblockingacertainrangeofIPaddresses
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.util.StringTokenizer;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassIPFilterimplementsFilter{
privateFilterConfigconfig;
publicfinalstaticStringIP_RANGE="192.168";
publicIPFilter(){}
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
this.config=filterConfig;
}
publicvoiddoFilter(ServletRequestrequest,
ServletResponseresponse,
FilterChainchain)throwsIOException,ServletException{
Stringip=request.getRemoteAddr();
HttpServletResponsehttpResp=null;
if(responseinstanceofHttpServletResponse)
httpResp=(HttpServletResponse)response;
//BreakuptheIPaddressintochunksrepresentingeachbyte
StringTokenizertoke=newStringTokenizer(ip,".");
intdots=0;
Stringbyte1="";
Stringbyte2="";
Stringclient="";
//
while(toke.hasMoreTokens()){
++dots;
//Thistokenisthefirstnumberseriesorbyte
if(dots==1){
byte1=toke.nextToken();
}else{
//Thistokenisthesecondnumberseriesorbyte
byte2=toke.nextToken();
break;//onlyinterestedinfirsttwobytes
}
}//while
//PiecetogetherhalfoftheclientIPaddresssoitcanbe
//comparedwiththeforbiddenrangerepresentedby
//IPFilter.IP_RANGE
client=byte1+"."+byte2;
//iftheclientIPfitstheforbiddenrange...
if(IP_RANGE.equals(client)){
httpResp.sendError(HttpServletResponse.SC_FORBIDDEN,
"Thatmeansgoodbyeforever!");
}else{
//Clientisokay;sendthemontheirmerryway
chain.doFilter(request,response);
}
}//doFilter
publicvoiddestroy(){
/*calledbeforetheFilterinstanceisremoved
fromservicebythewebcontainer*/
}
}
Thefilterobtainstheclient'sIPaddresswiththeServletRequest'sgetRemoteAddr()method.ThefilterthanparsesthereturnvaluetodetermineiftheIPaddressfallsintothe"192.168"range.IftheIPaddressdoesfallintothisrange,thenthecodecallstheHttpServletResponsesendError()methodwiththe"403Forbidden"typeHTTPstatuscode,asin:
httpResp.sendError(HttpServletResponse.SC_FORBIDDEN,
"Thatmeansgoodbyeforever!");
Thismethodcalleffectivelyshortcircuitstherequestbypreventingtheuserfromreachingtheiroriginaldestination.IftheIPaddressisacceptable,thecodecallschain.doFilter(),whichpassestherequestandresponseobjectsalongthefilterchain.Inthiscase,theapplicationdoesnotmapanyotherfilterstothanks.jsp,sothewebcontainerinvokesthatJSPpage.
Example19-17showsthemappingforthisfilterinweb.xml.ThefilterismappedtoallrequestswiththeURLmapping"/*."
Example19-17.ThemappingoftheIP-blockingfilter
<filter>
<filter-name>IPFilter</filter-name>
<filter-class>com.jspservletcookbook.IPFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>IPFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Figure19-4showsthepagethewebbrowserwilldisplayiftheclientIPaddressisblocked.
Figure19-4.AfilteredoutIPaddressreceivesanHTTPStatus403message
SeeAlso
Chapter9onhandlingerrorsinwebapplications;Recipe19.8onusingfilterswithRequestDispatchers;Recipe18.3onusingafiltertoalterthenforwardtherequest;Recipe19.1-Recipe19.4onmappingfilterstowebcomponents;Recipe19.5onconfiguringinitparametersforafilter;Recipe19.7onfilteringtheHTTPresponse;Recipe19.9on
checkingformparameterswithafilter.
Chapter20.ManagingEmailinServletsandJSPs
Introduction
Recipe20.1.PlacingtheEmail-RelatedClassesonyourClasspath
Recipe20.2.SendingEmailfromaServlet
Recipe20.3.SendingEmailfromaServletUsingaJavaBean
Recipe20.4.AccessingEmailfromaServlet
Recipe20.5.AccessingEmailfromaServletUsingaJavaBean
Recipe20.6.HandlingAttachmentsfromanEmailReceivedinaServlet
Recipe20.7.AddingAttachmentstoanEmailinaServlet
Recipe20.8.ReadingaReceivedEmail'sHeadersfromaServlet
Introduction
ThischapterdescribeshowtomanageemailinyourservletsusingtheJavaMailandJavaBeansActivationFramework(JAF)APIs.JavaMailprovidesJavaclassesfordealingwithmostaspectsofcreating,sending,andaccessingemail.TheJAFisaseparateAPIforhandlingthedatatypesandMultipurposeInternetMailExtension(MIME)typesyoumayencounterwhengeneratingemail,suchasthemanydifferentkindsoffileattachments.BothoftheseAPIsareapartoftheJava2EnterpriseEdition(J2EE)platform.
JavaMailmodelsanemailsystemwithclassesthatrepresentmailsessions(thejavax.mail.Sessionclass),messagestores(thejavax.mail.Storeclass),folders(thejavax.mail.Folderclass,suchastheINBOXfolder),emailmessages(javax.mail.Message),andemailaddresses(thejavax.mail.internet.InternetAddressclass).Forexample,anemailmessageissimilartoaJavaBean,withsettermethodstobuildthevariousmessagecomponents(e.g.,setFrom(),setRecipients(),setSubject(),etc.).
Thefollowingrecipesshowhowtomanagebasicemailmessagingusingasingleservlet,aswellasmethodsforseparatingtheresponsibilityforemailingandhandlingHTTPrequestsintoJavaBeansandservlets.
Recipe20.1PlacingtheEmail-RelatedClassesonyourClasspath
Problem
Youwanttousethejavax.mailandrelatedJavapackagestohandleemailinaservlet.
Solution
DownloadtheZIPfilescontainingthemail.jarandactivation.jararchives.AddtheseJARfilestoashareddirectoryforJARfileswhosecontentsareloadedbythewebcontainer.Ifthisdirectorytypeisnotavailable,addthemail.jarandactivation.jarfilestotheWEB-INF/libdirectoryofyourwebapplication.
Discussion
IfyourclasspathforcompilingservletsalreadyincludestheJARfilesmadeavailablebyyourwebcontainer(suchastheJARfilesinTomcat'scommon/libdirectory),testifanemail-relatedservletsuchasExample20-1compilessuccessfully.Ifthecompilerreportsthatthepackagesjavax.mailandjavax.mail.internetdonotexist,youmustaddtheproperJARfilestoyourclasspath.
SeeRecipe4.3onusingAnttoincludeTomcat'sJARfilesinyourclasspath.
Downloadthemail.jarcomponentfromhttp://java.sun.com/products/javamail/.ThedownloadedfileisaZIParchivecontainingthemail.jararchive.Thisfileincludestherequiredpackagesforhandlingemailinaservlet,suchasjavax.mailandjavax.mail.internet.
ThendownloadtheJAFfromhttp://java.sun.com/products/javabeans/glasgow/jaf.html.Servletscanusetheseclasses,aspartofthejavax.activationpackage,tohandlethedifferentdatatypesthatcanbetransferredwithemailmessages,suchasfileattachments.
YoucanhandlebasicfileattachmentsusingtheJavaMailAPIalone(withoutJAF),asinRecipe20.5andRecipe20.6.SeeRecipe20.7forexamplesofhowtousesomeofthejavax.activationclassestoaddfileattachmentstoemails.
Addthemail.jarandactivation.jararchivestotheWEB-INF/libdirectoryofyourwebapplicationtomaketheJavaMailandJAFpackagesavailabletoaservlet.
SeeAlso
TheSunMicrosystemsJavaMailAPIpage:http://java.sun.com/products/javamail/;theJAFwebpage:http://java.sun.com/products/javabeans/glasgow/jaf.html;Recipe20.2onsendingemailfromaservlet;Recipe20.3onsendingemailusingaJavaBean;Recipe20.4coveringhowtoaccessemailinaservlet;Recipe20.5onaccessingemailwithaJavaBean;Recipe20.6onhandlingattachmentsinaservlet;Recipe20.7onaddingattachmentstoanemailmessage;Recipe20.8onreadinganemail'sheaders.
Recipe20.2SendingEmailfromaServlet
Problem
Youwanttosendemailsfromaservlet.
Solution
Importthejavax.mailandjavax.mail.internetpackagesatthetopoftheservletsourcecode.CreateasendMessage()method(oramethodwithadifferentname)thatcanbecalledfromtheservletmethodsdoGet()ordoPost().
Discussion
ThesendMessage()methodinExample20-1usestheJavaMailAPItoconnectwithamailserver,constructanemailmessage,andthensendthatmessagetooneormorerecipients.Theservletobtainsthevariouscomponentsofanemailthetargetemailaddress,thesender'saddress,thesubjectfield,andtheemail'sbodycontentfromrequestparameters.Theservletcanhandleaformsubmittedbyaclientusingawebbrowser.
Theformtagmightlooklikethis:
<formmethod="POST"action=
"/home/servlet/com.jspservletcookbook.EmailServlet">
Example20-1callsthesendMessage()methodfromtheservicemethoddoPost().ThesendMessage()methodparameterscomprisethepartsofanemail:theSMTPserver,therecipientofthe
email(thevariableto),the"from"addressofthesender,theemailsubject,andtheemail'scontent.
Example20-1.Aservletsendsemailbasedonrequestparametervalues
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.util.Properties;
importjavax.mail.*;
importjavax.mail.internet.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassEmailServletextendsHttpServlet{
//defaultvalueformailserveraddress,incasetheuser
//doesn'tprovideone
privatefinalstaticStringDEFAULT_SERVER="mail.attbi.com";
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//obtainthevaluesforemailcomponentsfrom
//requestparameters
StringsmtpServ=request.getParameter("smtp");
if(smtpServ==null||smtpServ.equals(""))
smtpServ=DEFAULT_SERVER;
Stringfrom=request.getParameter("from");
Stringto=request.getParameter("to");
Stringsubject=request.getParameter("subject");
StringemailContent=request.getParameter("emailContent");
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Emailmessagesender</title></head><body>");
try{
sendMessage(smtpServ,to,from,subject,emailContent);
}catch(Exceptione){
thrownewServletException(e.getMessage());
}
out.println(
"<h2>Themessagewassentsuccessfully</h2>");
out.println("</body></html>");
}//doPost
privatevoidsendMessage(StringsmtpServer,Stringto,Stringfrom,
Stringsubject,StringemailContent)throwsException{
Propertiesproperties=System.getProperties();
//populatethe'Properties'objectwiththemail
//serveraddress,sothatthedefault'Session'
//instancecanuseit.
properties.put("mail.smtp.host",smtpServer);
Sessionsession=Session.getDefaultInstance(properties);
MessagemailMsg=newMimeMessage(session);//anewemailmessage
InternetAddress[]addresses=null;
try{
if(to!=null){
//throws'AddressException'ifthe'to'emailaddress
//violatesRFC822syntax
addresses=InternetAddress.parse(to,false);
mailMsg.setRecipients(Message.RecipientType.TO,addresses);
}else{
thrownewMessagingException(
"Themailmessagerequiresa'To'address.");
}
if(from!=null){
mailMsg.setFrom(newInternetAddress(from));
}else{
thrownewMessagingException(
"Themailmessagerequiresavalid'From'address.");
}
if(subject!=null)
mailMsg.setSubject(subject);
if(emailContent!=null)
mailMsg.setText(emailContent);
//Finally,sendthemailmessage;throwsa'SendFailedException'
//ifanyofthemessage'srecipientshaveaninvalidaddress
Transport.send(mailMsg);
}catch(Exceptionexc){
throwexc;
}
}//sendMessage
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//doGet()callsdoPost()...
doPost(request,response);
}//doGet
}//EmailServlet
Theservletinteractswithamailserverinthefollowingmanner:
1. Thecodecreatesajavax.mail.Sessionobject,whichcontainsvariousdefaultsandpropertyvalues(suchasmail.smtp.host)thattheotherJavaMailobjectswilluse.YoucanshareasingleSessionobjectinanapplication.
ThecodecreatesaMimeMessageobject(passingintheSessionasaconstructorparameter).
TheservletthenpopulatestheMimeMessagewithanemail'svariouscomponents,suchasthe"to"and"from"emailaddresses,theemailsubject,aswellasthemessagecontent.
Thecodesendstheemailusingthejavax.mail.Transportstaticsend()method.
SeeAlso
TheSunMicrosystemsJavaMailAPIpage:http://java.sun.com/products/javamail/;Recipe20.1onaddingJavaMail-relatedJARstoyourwebapplication;Recipe20.3onsendingemailusingaJavaBean;Recipe20.4coveringhowtoaccessemailinaservlet;Recipe20.5onaccessingemailwithaJavaBean;Recipe20.6onhandlingattachmentsinaservlet;Recipe20.7onaddingattachmentstoanemailmessage;Recipe20.8onreadinganemail'sheaders.
Recipe20.3SendingEmailfromaServletUsingaJavaBean
Problem
YouwanttouseaJavaBeanorhelperclasstosendemailfromaservlet.
Solution
DevelopaJavaclassthatimplementsasendMessage()method(justanameIgaveit)toconstructanemailandsendit.StorethenewclassintheWEB-INF/classesfolderofthewebapplication,includingtheclass'spackage-relatedfolders.
Discussion
YoumaychoosetoseparatetheresponsibilitiesofhandlingHTTPrequestsandmanagingemailbyencapsulatingthesetasksinseparateclasses.AJavaBeanthatprovidestheessentialfunctionofsendingemailfitsthebillhere.
Recipe20.5andRecipe20.6showJavaBeansthatareusedtoaccessemailandhandleattachments.Abeanthatdoeseverythingemail-relatedgrowsfairlylargeinsize,sodevelopersmustmakeadesigndecisionaboutwhethertoseparatethesetasksintodifferentJavaBeans(orutilityclasses)thatcanbeusedfromservlets.
CreatethebeanandstoreitintheWEB-INF/classesfolder.Example20-
3showsthedoGet()methodofanHttpServletusingaJavaBeantosendanemail.Example20-2showsthebeanclassitself.ThedifferencebetweenthesendMessage()methodofExample20-1andtheoneinExample20-2isinthewaythebeanreceivesthevariousemailparts,suchastherecipient'semailaddress.Thebeanstoresthesepartsaspropertiesandusessettermethodstoprovidethepropertyvalues.
Ontheotherhand,Example20-1usesrequestparametersandmethodargumentstoprovidethesevalues.
Example20-2.AJavaBeanusedtosendemail
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.util.Properties;
importjavax.mail.*;
importjavax.mail.internet.*;
publicclassEmailBean{
publicEmailBean(){}
//setdefaults
privatefinalstaticStringDEFAULT_CONTENT="Unknowncontent";
privatefinalstaticStringDEFAULT_SUBJECT="Unknownsubject";
privatestaticStringDEFAULT_SERVER=null;
privatestaticStringDEFAULT_TO=null;
privatestaticStringDEFAULT_FROM=null;
static{
//setMaildefaultsbasedonapropertiesfile
java.util.ResourceBundlebundle=
java.util.ResourceBundle.
getBundle("com.jspservletcookbook.mailDefaults");
DEFAULT_SERVER=bundle.getString("DEFAULT_SERVER");
DEFAULT_TO=bundle.getString("DEFAULT_TO");
DEFAULT_FROM=bundle.getString("DEFAULT_FROM");
}//static
//JavaBeanproperties
privateStringsmtpHost;
privateStringto;
privateStringfrom;
privateStringcontent;
privateStringsubject;
publicvoidsendMessage()throwsException{
Propertiesproperties=System.getProperties();
//populatethe'Properties'objectwiththemail
//serveraddress,sothatthedefault'Session'
//instancecanuseit.
properties.put("mail.smtp.host",smtpHost);
Sessionsession=Session.getDefaultInstance(properties);
MessagemailMsg=newMimeMessage(session);//anewemailmessage
InternetAddress[]addresses=null;
try{
if(to!=null){
//throws'AddressException'ifthe'to'emailaddress
//violatesRFC822syntax
addresses=InternetAddress.parse(to,false);
mailMsg.setRecipients(Message.RecipientType.TO,addresses);
}else{
thrownewMessagingException(
"Themailmessagerequiresa'To'address.");
}
if(from!=null){
mailMsg.setFrom(newInternetAddress(from));
}else{
thrownewMessagingException(
"Themailmessagerequiresavalid'From'address.");
}
if(subject!=null)
mailMsg.setSubject(subject);
if(content!=null)
mailMsg.setText(content);
//Finally,sendthemailmessage;throwsa'SendFailedException'
//ifanyofthemessage'srecipientshaveaninvalidaddress
Transport.send(mailMsg);
}catch(Exceptionexc){
throwexc;
}
}//sendMessage
//Thesettermethodsareallthesamestructure,
//sowe'rejustshowingtwo
publicvoidsetSmtpHost(Stringhost){
if(check(host)){
this.smtpHost=host;
}else{
this.smtpHost=DEFAULT_SERVER;
}
}//setSmtpHost
publicvoidsetTo(Stringto){
if(check(to)){
this.to=to;
}else{
this.to=DEFAULT_TO;
}
}//setTo
/*--Notshown:'setter'methodscontinuewithexactlythesamestructurefor
'from','subject',and'content'--*/
privatebooleancheck(Stringvalue){
if(value==null||value.equals(""))
returnfalse;
returntrue;
}//check
}
Example20-3usesthejava.util.ResourceBundleclasstosetdefaultpropertyvaluesforvariablessuchasthenameoftheserver.ThemailDefaults.propertiesfileisstoredinWEB-INF/classes/com/jspservletcookbook.Hereisanexampleofthepropertiesfile'scontents:
DEFAULT_SERVER=smtp.comcast.net
Thebeanallowsthesettingofthevariousemailpartswiththefollowingmethods(Example20-3doesnotshowallofthem):setSmtpHost(),setTo(),setFrom(),setSubject(),andsetContent().
TheservletinExample20-3createsaninstanceofanEmailBean,setsthevariouspartsoftheemailmessage,thencallsthesendMessage()method.Example20-3showsonlythedoGet()method.Theservlet'sdoPost()methodcouldcalldoGet()asin:doGet(request,response).
Example20-3.AservletusestheJavaBeantosendemail
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Emailmessagesender</title></head><body>");
EmailBeanemailer=newEmailBean();
emailer.setSmtpHost("mail.attbi.com");
emailer.setTo("[email protected]");
emailer.setFrom("[email protected]");
emailer.setSubject("Thisisnotspam!");
emailer.setContent("PleasecallASAP.");
try{
emailer.sendMessage();
}catch(Exceptione){thrownewServletException(e);}
out.println("</body></html>");
}//doGet
ThebeanitselfthrowsMessagingExceptionsif,forinstance,the"to"emailaddressthattheuserprovidesisinaninvalidformat.Thebeanrethrowsanyexceptionsthatitcatcheswhilebuildingandsendingtheemail.
SeeAlso
Recipe20.4coveringhowtoaccessemailinaservlet;Recipe20.5onaccessingemailwithaJavaBean;Recipe20.6onhandlingattachmentsinaservlet;Recipe20.7onaddingattachmentstoanemailmessage;Recipe20.8onreadinganemail'sheaders.
Recipe20.4AccessingEmailfromaServlet
Problem
Youwanttoaccessanddisplaythecontentofemailinaservlet.
Solution
UsetheJavaMailAPIandamethodinsidetheservlettohandleanddisplaythevaluesofemailmessages.
Discussion
FetchingemailmessagesusingJavaMailandaservletisastraightforwardprocess:
1. Importthejavax.mailandjavax.mail.internetpackagesatthetopoftheservletsourcecode.
Insidetheservlet'smail-fetchingmethod,createajavax.mail.Sessionobjecttohandlethismailsession.
Getamessagestoreobject(ajavax.mail.Store)fromthesessiontorepresentthePOP3mailaccount.
ConnecttotheStoreusingtheconnect(Stringhost,Stringuser,Stringpassword)methodoftheStoreobject(thereareoverloadedversionsofthismethod).TheStoreisdesignedtoauthenticateauserandconnectwithamailserver.
AccesstheINBOXfolderfromthemessagestore.
ObtainanymessagesthatfoldercontainsasaMessage[]type,thendowhateveryouwantwitheachmessage,iteratingthroughthearray.
Example20-4fetchesemailmessagesbycallingitshandleMessages()methodinthedoGet()servicemethod.
Example20-4.Aservletthatfetchesemailmessages
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.util.Properties;
importjavax.mail.*;
importjavax.mail.internet.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassMailAccessorextendsHttpServlet{
privatefinalstaticStringDEFAULT_SERVER="mail.attbi.com";
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head><title>EmailReader</title></head><body>");
//Thismethodaccessesanyemailanddisplaysthecontents
handleMessages(request,out);
out.println("</body></html>");
}//doGet
privatevoidhandleMessages(HttpServletRequestrequest,
PrintWriterout)throwsIOException,ServletException{
//ObtainuserauthenticationinformationforaPOPserver,
//usedtoaccessemail.Thisinformationisstoredina
//HttpSessionobject
HttpSessionhttpSession=request.getSession();
Stringuser=(String)httpSession.getAttribute("user");
Stringpassword=(String)httpSession.getAttribute("pass");
StringpopAddr=(String)httpSession.getAttribute("pop");
StorepopStore=null;
Folderfolder=null;
if(!check(popAddr))
popAddr=MailAccessor.DEFAULT_SERVER;
try{
//basiccheckfornulloremptyuserandpassword
if((!check(user))||(!check(password)))
thrownewServletException(
"Avalidusernameandpasswordisrequired.");
Propertiesproperties=System.getProperties();
//Obtaindefault'Session'forthisinteractionwith
//amailserver
Sessionsession=Session.getDefaultInstance(properties);
//Obtainamessagestore(i.e.,aPOP3emailaccount,from
//theSessionobject
popStore=session.getStore("pop3");
//connecttothestorewithauthenticationinformation
popStore.connect(popAddr,user,password);
//GettheINBOXfolder,openit,andretireveanyemails
folder=popStore.getFolder("INBOX");
if(!folder.exists())
thrownewServletException(
"An'INBOX'folderdoesnotexistfortheuser.");
folder.open(Folder.READ_ONLY);
Message[]messages=folder.getMessages();
intmsgLen=messages.length;
if(msgLen==0){
out.println(
"<h2>TheINBOXfolderdoesn'tcontainanyemail"+
"messages.</h2>");}
//foreachretrievedmessage,usedisplayMessagemethodto
//displaythemailmessage
for(inti=0;i<msgLen;i++){
displayMessage(messages[i],out);
out.println("<br/><br/>");
}
}catch(Exceptionexc){
out.println(
"<h2>Sorry,anerroroccurredwhileaccessingtheemail"+
"messages.</h2>");
out.println(exc.toString());
}finally{
try{
//closethefolderandthestoreinthefinallyblock
//if'true'parameter,anydeletedmessageswillbeexpunged
//fromtheFolder
if(folder!=null)
folder.close(false);
if(popStore!=null)
popStore.close();
}catch(Exceptione){}
}
}//printMessages
privatevoiddisplayMessage(Messagemsg,PrintWriterout)
throwsMessagingException,IOException{
if(msg!=null&&msg.getContent()instanceofString){
if(msg.getFrom()[0]instanceofInternetAddress){
out.println(
"Messagereceivedfrom:"+
((InternetAddress)msg.getFrom()[0]).getAddress()+
"<br/>");
}
out.println("Messagecontenttype:"+msg.getContentType()+
"<br/>");
out.println("Messagebodycontent:"+
(String)msg.getContent());
}else{
out.println(
"<h2>Thereceivedemailmessagewasnotofatext"+
"contenttype.</h2>");
}//outerif
}//displayMessage
privatebooleancheck(Stringvalue){
if(value==null||value.equals(""))
returnfalse;
returntrue;
}//check
}
ThedisplayMessage()methoddisplayseachmessage's"from"address,themessage'scontenttype(i.e.,theMIMEtypeasintext/plain),andtheemail'scontent.YoucangettheStringfromatypicalemailmessagethatcontainsjustheadersandthetextmessagebycallingMessage.getContent().Gettingthe"from"addressisalittletrickier:
out.println("Messagereceivedfrom:"+
((InternetAddress)msg.getFrom()[0]).getAddress()+"<br/>");
TheMessage.getFrom()methodreturnsanarrayofjavax.mail.Addressobjects.Thiscodeisdesignedtoaccessthefirstemailaddress,sinceanemailistypicallysentbyonepartytoitsrecipient(notincludingthosemaliciousspammers,ofcourse).
Thecodeaccessesthefirstarraymember,caststhereturnvaluetoajavax.mail.InternetAddress,thencallsgetAddress()onthatobject,whichreturnstheStringemailaddress.
Figure20-1showstheservlet'sreturnvalueinabrowserwindow.Sincetheservletreceivesitsemailauthenticationinformationfromsession
attributes,thefirstrequesttargetsaJSP,whichsetsthesessionattributes.ThentheJSPforwardstherequesttotheMailAccessorservlet.Theservletdisplayseachreceivedemailseparatedbytwolinebreaks.Inotherwords,theinformationtheservletdisplaysabouteachemailincludeswhosenttheemail,themail'scontenttype,andthecontentofthemessageitself.
Figure20-1.Aservletfetchesanddisplaystwoemailmessages
SeeAlso
Chapter16onsettingsessionattributes;Chapter25onaccessingajavax.mail.SessionJNDIobjectonBEAWebLogic;SunMicrosystem'sJavaMailAPIpage:http://java.sun.com/products/javamail/;Recipe20.1onaddingJavaMail-relatedJARstoyourwebapplication;Recipe20.2onsendingemailusingaservlet;Recipe20.3onsendingemailusingaJavaBean;Recipe20.5onaccessingemailwithaJavaBean;Recipe20.6onhandlingattachmentsinaservlet;Recipe20.7onaddingattachmentstoanemailmessage;Recipe20.8onreadinganemail'sheaders.
Recipe20.5AccessingEmailfromaServletUsingaJavaBean
Problem
YouwanttouseaJavaBeanorhelperclasstoaccessanddisplayemailmessages.
Solution
AddthehandleMessages()anddisplayMessage()methodsfromExample20-4totheJavaBeanclassdefinedinExample20-2.ThenusetheJavaBeanfromaservlet'sdoGet()ordoPost()method.
Discussion
WhenwelastencounteredtheEmailBeaninExample20-2itcontainedasendMessage()method,alongwithseveralproperty"setter"methods(suchassetSmtpHost(Stringhost)).IfyouaddthehandleMessages()anddisplayMessage()methodsfromExample20-4tothissameclass,youcanusetheJavaBeantobothsendandaccessemail.
ThiscodeinhandleMessages()fromExample20-4needstobechangedtoincludetheEmailBeanclassname:
//staticreferencetoaconstantvalue
if(!check(popAddr))
popAddr=EmailBean.DEFAULT_SERVER;
However,theEmailBeanclasswillhavegrownquitelargeasaresultofaddingthetwomethods,soyoumightcreatetwoJavaBeansoneforsendingmailandanotherforaccessingit.Example20-5createsandusesaninstanceofaspecialemailJavaBean.YoumuststorethebeanclassintheWEB-INF/classesdirectoryorinaJARfileinWEB-INF/lib.
Example20-6alsoshowsaJavaBeanthatdefineshandleMessages()anddisplayMessage()fordealingwithemailattachments.
Example20-5.AservletusesaJavaBeantoaccessemailmessages
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Emailmessagesender</title></head><body>");
EmailBeanemailer=newEmailBean();
emailer.setSmtpHost("mail.attbi.com");
emailer.handleMessages(request,out);
out.println("</body></html>");
}//doGet
SeeAlso
SunMicrosystem'sJavaMailAPIpage:http://java.sun.com/products/javamail/;Recipe20.1onaddingJavaMail-relatedJARstoyourwebapplication;Recipe20.2onsendingemailfromaservlet;Recipe20.3onsendingemailusingaJavaBean;Recipe20.4coveringhowtoaccessemailinaservlet;Recipe20.6onhandlingattachmentsinaservlet;Recipe20.7onaddingattachmentstoanemailmessage;Recipe20.8onreadinganemail'sheaders.
Recipe20.6HandlingAttachmentsfromanEmailReceivedinaServlet
Problem
Youwanttoreadanemailmessageandsaveanyattachmentsfromaservlet.
Solution
UsetheJavaMailAPIandaspecialJavaBeantosavetheInputStreamsfromattachedfilestoaspecifiedfolder.
Discussion
AccessingemailusuallyinvolvesauthenticatingauserwithaPOPaccount,thenconnectingwiththemailserveranddownloadinganyemailmessages.Example20-6usestheSession,Store,Folder,andMessageclassesfromtheJavaMailAPItodownloadanarrayofMessagesfromaparticularuser'semailaccount.However,theservletinRecipe20.4wasdesignedtodealonlywithMessageswhosecontentwasoftypeString(thereturnvalueoftheMessage.getContent()method).
IftheMessage'scontentisoftypeMultipart,thentheprocessofhandlingattachmentsmirrorsthepeelingofanonionmorecodeisinvolved.Example20-6separatestheemail-relatedcodeintoaJavaBeanthatcanbeusedfromaservlet.Thebean'sdisplayMessage()methodteststhecontentofeachMessage.IfthecontentisoftypeMultipart,thenthecodeexamineseachcontained
BodyPart.
PictureaMultipartmessagetypeasacontainer.Thecontainer'sheadersarelikeanyotheremailmessage'sheaders(butwithdifferentvalues).ThecontainerenclosesBodyParts,whicharelikemessagesinsideofmessages.SomeBodyPartsrepresentthetextmessageaccompanyingaMultipartemailmessage.OtherBodyPartsrepresenttheattachedfiles,suchasaMicrosoftWordfileorJPEGimage.
IftheBodyPart'scontentisaString,thenthebeandisplaysthetextmessage.Otherwise,thebeanassumestheBodyPartisanattachedfile;itsavesthefiletoaspecialattachmentsfolder.You'reprobablyalreadyfamiliarwiththehandleMessages()code,soyoucanskiptothedisplayMessage()method,whichdealswithsavinganyfileattachments.
Example20-6.AJavaBeanthathandlesattachmentsanddeliversabrowsermessage
packagecom.jspservletcookbook;
importjava.io.*;
importjava.util.Properties;
importjavax.mail.*;
importjavax.mail.internet.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassAttachBean{
/*NOTSHOWN:privatebeanfields(or,properties);defaultvariables;
andthesendMessagemethod
SeeExample20-2*/
publicAttachBean(){}
privatevoidhandleMessages(HttpServletRequestrequest,
PrintWriterout)throwsIOException,ServletException{
/*gettheuserandpasswordinformationforaPOP
accountfromanHttpSessionobject*/
HttpSessionhttpSession=request.getSession();
Stringuser=(String)httpSession.getAttribute("user");
Stringpassword=(String)httpSession.getAttribute("pass");
StringpopAddr=(String)httpSession.getAttribute("pop");
StorepopStore=null;
Folderfolder=null;
if(!check(popAddr))
popAddr=AttachBean.DEFAULT_SERVER;
try{
if((!check(user))||(!check(password)))
thrownewServletException(
"Avalidusernameandpasswordisrequiredtocheckemail.");
Propertiesproperties=System.getProperties();
Sessionsession=Session.getDefaultInstance(properties);
popStore=session.getStore("pop3");
popStore.connect(popAddr,user,password);
folder=popStore.getFolder("INBOX");
if(!folder.exists())
thrownewServletException(
"An'INBOX'folderdoesnotexistfortheuser.");
folder.open(Folder.READ_ONLY);
Message[]messages=folder.getMessages();
intmsgLen=messages.length;
if(msgLen==0)
out.println(
"<h2>TheINBOXfolderdoesnotyetcontainany"+
"emailmessages.</h2>");
for(inti=0;i<msgLen;i++){
displayMessage(messages[i],out);
out.println("<br/><br/>");
}//for
}catch(Exceptionexc){
out.println(
"<h2>Sorry,anerroroccurredwhileaccessing"+
"theemailmessages.</h2>");
out.println(exc.toString());
}finally{
try{
if(folder!=null)
folder.close(false);
if(popStore!=null)
popStore.close();
}catch(Exceptione){}
}
}//handleMessages
privatevoiddisplayMessage(Messagemsg,PrintWriterout)
throwsMessagingException,IOException{
if(msg!=null){
/*getthecontentofthemessage;themessagecould
beanemailwithoutattachments,oranemail
withattachments.ThemethodgetContent()willreturnan
instanceof'Multipart'ifthemsghasattachments*/
Objecto=msg.getContent();
if(oinstanceofString){
//justdisplaysomeinfoaboutthemessagecontent
handleStringMessage(msg,(String)o,out);
}elseif(oinstanceofMultipart){
//savetheattachment(s)toafolder
Multipartmpart=(Multipart)o;
Partpart=null;
Filefile=null;
FileOutputStreamstream=null;
InputStreaminput=null;
StringfileName="";
//eachMultipartismadeupof'BodyParts'that
//areoftype'Part'
for(inti=0;i<mpart.getCount();i++){
part=mpart.getBodyPart(i);
ObjectpartContent=part.getContent();
if(partContentinstanceofString){
handleStringMessage(msg,(String)partContent,
out);
}else{//handleasafileattachment
fileName=part.getFileName();
if(!check(fileName)){//defaultfilename
fileName="file"+
newjava.util.Date().getTime();}
//writetheattachment'sInputStreamtoafile
file=newFile(attachFolder+
System.getProperty("file.separator")+fileName);
stream=newFileOutputstream(file);
input=part.getInputStream();
intch;
while((ch=input.read())!=-1){
stream.write(ch);}
input.close();
out.println(
"Handledattachmentnamed:"+
fileName+"<br/><br/>");
}//if
}//for
}//elseifinstanceofmultipart
}else{
out.println(
"<h2>Thereceivedemailmessagereturnednull.</h2>");
}//ifmsg!=null
}//displayMessage
privatevoidhandleStringMessage(Partpart,StringemailContent,
PrintWriterout)throwsMessagingException{
if(partinstanceofMessage){
Messagemsg=(Message)part;
if(msg.getFrom()[0]instanceofInternetAddress){
out.println("Messagereceivedfrom:"+
((InternetAddress)msg.getFrom()[0]).getAddress()+
"<br/>");
}
out.println(
"Messagecontenttype:"+msg.getContentType()+
"<br/>");
out.println("Messagecontent:"+emailContent+"<br/>");
}
}
privatebooleancheck(Stringvalue){
if(value==null||value.equals(""))
returnfalse;
returntrue;
}//check
/*NOTSHOWN:various'setter'methodsforthebean'sproperties
SeeExample20-2*/
}//AttachBean
OncethedisplayMessage()codeidentifiesaBodyPartasanattachedfile,itreceivesthebytesthatrepresentthefileasanInputStream.ABodyPartimplementsthePartinterface,which
definesthemethodgetInputStream().ThecodesavesthefileusingtheInputStreamandthejava.io.FileOutputStreamclass.
Example20-7showsthedoGet()methodofaservletusingcom.jspservletcookbook.AttachBean.
Example20-7.Aservlet'sdoGet()methodusesaJavaBeantodealwithemailattachments
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Emailmessagesender</title></head><body>");
AttachBeanemailer=newAttachBean();
emailer.setSmtpHost("mail.attbi.com");
emailer.setAttachFolder(getServletContext().getRealPath("/")+"attachments");
emailer.handleMessages(request,out);
out.println("</body></html>");
}//doGet
Figure20-2showsthemessagesthattheservlet(usingtheJavaBean)displaysinabrowser.Thefirstemailisasimpletextmessagewithoutattachments.Thesecondemailcontainstwoattachments;itsMIMEtypeismultipart/mixed.
Figure20-2.Aservletdisplaysinformationaboutreceivedattachmentsandmessages
SeeAlso
SunMicrosystem'sJavaMailAPIpage:http://java.sun.com/products/javamail/;Recipe20.1onaddingJavaMail-relatedJARstoyourwebapplication;Recipe20.2onsendingemailfromaservlet;Recipe20.3onsendingemailusingaJavaBean;Recipe20.4coveringhowtoaccessemailinaservlet;Recipe20.5onaccessingemailwithaJavaBean;Recipe20.7onaddingattachmentstoanemailmessage;Recipe20.8onreadinganemail'sheaders.
Recipe20.7AddingAttachmentstoanEmailinaServlet
Problem
Youwanttobuildanemailmessagewithattachmentsinaservlet.
Solution
UsetheJavaMailAPIforbasicemailmessaging,andthetheJavaBeansActivationFramework(JAF)togeneratethefileattachments.
Discussion
TheJAFclassesprovidefine-grainedcontroloversettingupafileattachmentforanemailmessage.
IfyouareusingboththeJavaMailAPIandtheJAF,makesuretoimportthepackagesinyourservletclass:
importjavax.activation.*;
importjavax.mail.*;
importjavax.mail.internet.*;
//classdefinitioncontinues
ThesendMessage()methodinExample20-8createsanewemailmessage(specifically,anewjavax.mail.internet.MimeMessage),addsitstextmessage,andinsertsafileattachmentinsidethemessage.ThemethodthensendsthemessageusingthecodeyoumayhaveseeninRecipe20.2andRecipe20.3:
Transport.send(mailMsg);
Toaccomplishthis,thecodecreatesacontainer(ajavax.mail.Multipartobject)andtwojavax.mail.BodyPartsthatmakeupthethecontainer.ThefirstBodyPartisatextmessage(usedusuallytodescribethefileattachmenttotheuser),whilethesecondBodyPartisthefileattachment(inthiscase,aMicrosoftWordfile).ThenthecodesetsthecontentoftheMimeMessagetotheMultipart.Inanutshell,theMimeMessage(anemailmessage)containsaMultipart,whichitselfiscomposedoftwoBodyParts:theemail'stextmessageandanattachedfile.
IfyouwanttolookattheheadersofaMimeMessagethatcontainsattachments,callthegetAllHeaders()methodontheMimeMessage.SeeRecipe20.8fordetails.
Example20-8.Makingemailattachmentinaservlets
packagecom.jspservletcookbook;
importjava.io.*;
importjava.util.Properties;
importjavax.activation.*;
importjavax.mail.*;
importjavax.mail.internet.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassEmailAttachServletextendsHttpServlet{
//defaultvalueformailserveraddress,incasetheuser
//doesn'tprovideone
privatefinalstaticStringDEFAULT_SERVER="mail.attbi.com";
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Emailmessagesender</title></head><body>");
StringsmtpServ=request.getParameter("smtp");
if(smtpServ==null||smtpServ.equals(""))
smtpServ=DEFAULT_SERVER;
Stringfrom=request.getParameter("from");
Stringto=request.getParameter("to");
Stringsubject=request.getParameter("subject");
try{
sendMessage(smtpServ,to,from,subject);
}catch(Exceptione){
thrownewServletException(e.getMessage());
}
out.println(
"<H2>Yourattachmenthasbeensent.</H2>");
out.println("</body></html>");
}//doPost
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
doPost(request,response);
}//doGet
privatevoidsendMessage(StringsmtpServ,Stringto,Stringfrom,
Stringsubject)throwsException{
Multipartmultipart=null;
BodyPartbpart1=null;
BodyPartbpart2=null;
Propertiesproperties=System.getProperties();
//populatethe'Properties'objectwiththemail
//serveraddress,sothatthedefault'Session'
//instancecanuseit.
properties.put("mail.smtp.host",smtpServ);
Sessionsession=Session.getDefaultInstance(properties);
MessagemailMsg=newMimeMessage(session);//anewemailmessage
InternetAddress[]addresses=null;
try{
if(to!=null){
//throws'AddressException'ifthe'to'emailaddress
//violatesRFC822syntax
addresses=InternetAddress.parse(to,false);
mailMsg.setRecipients(Message.RecipientType.TO,addresses);
}else{
thrownewMessagingException(
"Themailmessagerequiresa'To'address.");
}
if(from!=null){
mailMsg.setFrom(newInternetAddress(from));
}else{
thrownewMessagingException(
"Themailmessagerequiresavalid'From'address.");
}
if(subject!=null)
mailMsg.setSubject(subject);
//Thisemailmessage'scontentisa'Multipart'type
//TheMIMEtypeforthemessage'scontentis'multipart/mixed'
multipart=newMimeMultipart();
//Thetextpartofthismultipartemailmessage
bpart1=newMimeBodyPart();
StringtextPart=
"Hello,justthoughtyou'dbeinterestedinthisWordfile.";
//createtheDataHandlerobjectforthetextpart
DataHandlerdata=newDataHandler(textPart,"text/plain");
//setthetextBodyPart'sDataHandler
bpart1.setDataHandler(data);
//addthetextBodyParttotheMultipartcontainer
multipart.addBodyPart(bpart1);
//createtheBodyPartthatrepresentstheattachedWordfile
bpart2=newMimeBodyPart();
//createtheDataHandlerthatpointstoaFile
FileDataSourcefds=newFileDataSource(newFile(
"h:/book/chapters/chap1/chap1.doc"));
//Makesurethattheattachedfileishandledas
//theappropriateMIMEtype:application/mswordhere
MimetypesFileTypeMapftm=newMimetypesFileTypeMap();
//thesyntaxhereistheMIMEtypefollowedby
//spaceseparatedextensions
ftm.addMimeTypes("application/msworddocDOC");
fds.setFileTypeMap(ftm);
//TheDataHandlerisinstantiatedwiththe
//FileDataSourcewejustcreated
DataHandlerfileData=newDataHandler(fds);
//theBodyPartwillcontainthewordprocessingfile
bpart2.setDataHandler(fileData);
//addthesecondBodyPart,theonecontainingtheattachment,to
//theMultipartobject
multipart.addBodyPart(bpart2);
//finally,setthecontentoftheMimeMessagetothe
//Multipartobject
mailMsg.setContent(multipart);
//sendthemailmessage;throwsa'SendFailedException'
//ifanyofthemessage'srecipientshaveaninvalidadress
Transport.send(mailMsg);
}catch(Exceptionexc){
throwexc;
}//try
}//sendMessage
}//EmailAttachServlet
ThecommentsinExample20-8explainwhathappenswhenyouusethejavax.activationclassestocreateafileattachmentoftheintendedMIMEtype.Themostconfusingpartiscreatingajavax.activation.FileDataSourcethatpointstothefilethatyouwanttoattachtotheemailmessage.ThecodeusestheFileDataSourcetoinstantiatethejavax.activation.DataHandler,whichisresponsibleforthecontentofthefileattachment.
//createtheDataHandlerthatpointstoaFile
FileDataSourcefds=newFileDataSource(newFile(
"h:/book/chapters/chap1/chap1.doc"));
MakesurethattheMimeMessageidentifiestheattachedfileasaMIMEtypeofapplication/msword,sothattheuser'semailapplicationcantrytohandletheattachmentasaMicrosoftWordfile.SettheFileTypeMapoftheFileDataSourcewiththefollowingcode:
//Makesurethattheattachedfileishandledas
//theappropriateMIMEtype:application/mswordhere
MimetypesFileTypeMapftm=newMimetypesFileTypeMap();
//thesyntaxhereistheMIMEtypefollowedby
//spaceseparatedextensions
ftm.addMimeTypes("application/msworddocDOC");
fds.setFileTypeMap(ftm);
AMimetypesFileTypeMapisaclassthatassociatesMIMEtypes(likeapplication/msword)withfileextensionssuchas.doc.
MakesureyouassociatethecorrectMIMEtypewiththefilethatyouaresendingasanattachment,sinceyouexplicitlymakethisassociationinthecode.Seehttp://java.sun.com/j2ee/1.4/docs/api/javax/activation/MimetypesFileTypeMap.htmlforfurtherdetails.
Thenthecodeperformsthefollowingsteps:
1. CreatesaDataHandlerbypassingthisFileDataSourceinasaconstructorparameter.
SetsthecontentoftheBodyPartwiththatDataHandler.
AddstheBodyParttotheMultipartobject(whichinturnrepresentsthecontentoftheemailmessage).
SeeAlso
SunMicrosystem'sJavaMailAPIpage:http://java.sun.com/products/javamail/;theJAFwebpage:http://java.sun.com/products/javabeans/glasgow/jaf.html;Recipe20.1onaddingJavaMail-relatedJARstoyourwebapplication;Recipe20.2onsendingemailfromaservlet;Recipe20.3onsendingemailusingaJavaBean;Recipe20.4coveringhowtoaccessemailinaservlet;Recipe20.5onaccessingemailwithaJavaBean;Recipe20.6onhandlingattachmentsinaservlet;Recipe20.8onreadinganemail'sheaders.
Recipe20.8ReadingaReceivedEmail'sHeadersfromaServlet
Problem
Youwanttoreadtheheadersfromanemailinaservlet.
Solution
UsetheJavaMailAPItoaccesseachemailmessage.CallthegetAllHeaders()methodofthePartinterface,theniteratethroughtheEnumerationreturnvaluetogetthenameandvalueofeachheader.
Discussion
Anadvancedemailprogram,suchasaspamfilter,isdesignedtoexamineanemail'sheaders,notjustitsmessageandfileattachments.
Aheaderiscomposedofaname,acoloncharacter(:),andavalue.Theheadersprovidedetailsabouttheemailmessage,suchaswhosentthemessageandthemailserver(s)thathandledthemessageduringitsnetworktravels.Anexampleheaderis:
To:<[email protected]>
TheJavaMailAPImakesiteasytolistanemail'sheaders.TheMessageobjecthasagetAllHeaders()method(viathePartinterfacethattheMessageclassimplements).Thismethodreturnsajava.util.Enumeration,holdingacollectionof
javax.mail.Headerobjects.TogettheheadernameandvaluefromtheseHeaderobjects,justcalltheirgetName()andgetValue()methods.
ThePartinterfacealsohasagetHeader(StringheaderName)methodthatyoucanusetoobtainthevalueforaparticularheader.ThismethodreturnsaStringarraycontainingthevalue(s)fortheheaderofthatname.
Example20-9showsthesameservletfromRecipe20.4,revisedtolistboththemessagecontentsandtheheadervalues.Theheader-relatedcodeappearsinthedisplayMessage()method.
Example20-9.Aservletdisplaysemailheadernamesandvalues
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.util.Properties;
importjava.util.Enumeration;
importjavax.mail.*;
importjavax.mail.internet.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassHeaderAccessorextendsHttpServlet{
privatefinalstaticStringDEFAULT_SERVER="mail.attbi.com";
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head><title>EmailReader</title></head><body>");
handleMessages(request,out);
out.println("</body></html>");
}//doGet
privatevoidhandleMessages(HttpServletRequestrequest,
PrintWriterout)throwsIOException,ServletException{
HttpSessionhttpSession=request.getSession();
Stringuser=(String)httpSession.getAttribute("user");
Stringpassword=(String)httpSession.getAttribute("pass");
StringpopAddr=(String)httpSession.getAttribute("pop");
StorepopStore=null;
Folderfolder=null;
if(!check(popAddr))
popAddr=HeaderAccessor.DEFAULT_SERVER;
try{
if((!check(user))||(!check(password)))
thrownewServletException(
"Avalidusernameandpasswordisrequiredtocheckemail.");
Propertiesproperties=System.getProperties();
Sessionsession=Session.getDefaultInstance(properties);
popStore=session.getStore("pop3");
popStore.connect(popAddr,user,password);
folder=popStore.getFolder("INBOX");
if(!folder.exists())
thrownewServletException(
"An'INBOX'folderdoesnotexistfortheuser.");
folder.open(Folder.READ_ONLY);
Message[]messages=folder.getMessages();
intmsgLen=messages.length;
if(msgLen==0)
out.println(
"<h2>TheINBOXfolderdoesnotyetcontainany"+
"emailmessages.</h2>");
for(inti=0;i<msgLen;i++){
displayMessage(messages[i],out);
out.println("<br/><br/>");
}//for
}catch(Exceptionexc){
out.println(
"<h2>Sorry,anerroroccurredwhileaccessingthe"+
"emailmessages.</h2>");
out.println(exc.toString());
}finally{
try{
if(folder!=null)
folder.close(false);
if(popStore!=null)
popStore.close();
}catch(Exceptione){}
}
}//handleMessages
privatevoiddisplayMessage(Messagemsg,PrintWriterout)
throwsMessagingException,IOException{
if(msg!=null&&msg.getContent()instanceofString){
if(msg.getFrom()[0]instanceofInternetAddress){
out.println(
"Messagereceivedfrom:"+
((InternetAddress)msg.getFrom()[0]).getAddress()+"<br/>");
}
out.println("Messagecontenttype:"+msg.getContentType()+
"<br/>");
out.println(
"Messagebodycontent:"+(String)msg.getContent());
//Listeachoftheemailheadersusingaultag
out.println("<ul>");
Headerhead=null;
Enumerationheaders=msg.getAllHeaders();
while(headers.hasMoreElements()){
head=(Header)headers.nextElement();
out.println(
"<li>"+head.getName()+":"+head.getValue()+"</li>");
}//while
out.println("</ul>");
}else{
out.println(
"<h2>Thereceivedemailmessagewasnot"+
"atextcontenttype.</h2>");
}
}//displayMessage
privatebooleancheck(Stringvalue){
if(value==null||value.equals(""))
returnfalse;
returntrue;
}
}
Figure20-3showsthebrowserdisplayoftheservletinExample20-9.Eachoftheheadersisprecededbyabulletcharacter,followedbytheheadername,acolon,andtheheadervalue.
Figure20-3.Aservletaccessesanemailanddisplaysitsheaders
SeeAlso
SunMicrosystem'sJavaMailAPIpage:http://java.sun.com/products/javamail/;Recipe20.1onaddingJavaMail-relatedJARstoyourwebapplication;Recipe20.2onsendingemailfromaservlet;Recipe20.3onsendingemailusingaJavaBean;Recipe20.4coveringhowtoaccessemailinaservlet;Recipe20.5onaccessingemailwithaJavaBean;Recipe20.6onhandlingattachmentsinaservlet;Recipe20.7onaddingattachmentstoanemailmessage.
Chapter21.AccessingDatabasesIntroduction
Recipe21.1.AccessingaDatabasefromaServletWithoutDataSource
Recipe21.2.ConfiguringaDataSourceinTomcat
Recipe21.3.UsingaDataSourceinaServletwithTomcat
Recipe21.4.CreatingaDataSourceonWebLogic
Recipe21.5.UsingaJNDILookuptogetaDataSourcefromWebLogic
Recipe21.6.UsingaDataSourcefromWebLogicinaJSP
Recipe21.7.CallingaStoredProcedurefromaServlet
Recipe21.8.CallingaStoredProcedurefromaJSP
Recipe21.9.ConvertingaResultSettoaResultObject
Recipe21.10.ExecutingSeveralSQLStatementsWithinaSingleTransaction
Recipe21.11.UsingTransactionswithJSPs
Recipe21.12.FindingInformationaboutaResultSet
Introduction
IfyouareaJavawebdeveloperwhohasneverwrittendatabase-relatedcode,Ihavesomeadviceforyou:don'tholdyourbreathuntilyoureceivethistypeofassignment!
TheserecipesshowyouhowtoaccessadatabaseresourcebyusingaJavaNamingandDirectoryInterface(JNDI)lookup,whichisthemostefficient(andprobablythemostcommon)methodofaccessingdatabaseresourcesinaportablemanner.JNDIisaJavaAPIthatisdesignedtostoreobjectsinahierarchicaltreestructure,similartoafilesystemcomposedofdirectories,subdirectories,andfiles.ServletsandJSPscanthenusethemethodsoftheJNDIAPI(shownbyseveralexamplesinthischapter)toobtainreferencesfromJavaobjects,suchasJavaBeans,andusethemintheirprograms.
Fordatabasecode,thisusuallymeansjavax.sql.DataSourceobjects,whicharefactoriesfordatabaseconnections.TheDataSourcesprovide"connectionpools,"anotherveryimportantwebdatabasetool.Connectionpoolsaregroupsofdatabaseconnectionssharedbyservlets,JSPs,andotherclasses.ApplicationserverssuchasWebLogicusuallyallowyoutodeterminehowmanyconnectionsarestoredinthepool,whichdatabasetablecanbeusedbytheservertoautomaticallytestaconnectiontodetermineifitisfittobereturnedtothesharedpool,andotherpoolproperties.
TheserecipesexplainthebasicsofsettingupaconnectionpoolonbothTomcatandWebLogic.
Therecipesalsocoversomeotherpracticaldatabasetopics,suchashowtocallstoredproceduresinservletsandJSPs,aswellashowtoincludemorethanoneStructuredQueryLanguage(SQL)statementinatransaction.
Recipe21.1AccessingaDatabasefromaServletWithoutDataSource
Problem
YouwanttoaccessadatabasefromaservletwithoutaDataSourceconfigurationforthedatabase.
Solution
UsetheJavaDatabaseConnectivity(JDBC)APItoaccessajava.sql.Connectionobjectthatconnectstheservletwiththedatabase.
Discussion
Onoccasion,developersrequireaquick,lesselegantsolutiontoaccessingadatabase.Thisrecipeexplainshowtousethejava.sql.DriverManagerclasstoobtainaconnectiontoadatasourceinaservlet.TheDriverManagerclasscommunicateswithadatabasedriver,whichissoftwarethatallowsJavacodetointeractwithaparticulardatabase,suchasMySQLorOracle.
Thepreferreddesignistouseajavax.sql.Datasourcetogetadatabaseconnectionfromaconnectionpool,asdescribedinRecipe21.2-Recipe21.6.
Example21-1accomplishesthistaskinitsdoGet()servicemethod.
Example21-1.AservletaccessesadatabaseusingtheJDBCAPI
packagecom.jspservletcookbook;
importjava.sql.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassDatabaseServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
Stringsql="select*fromathlete";
Connectionconn=null;
Statementstmt=null;
ResultSetrs=null;
ResultSetMetaDatarsm=null;
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>ServletDatabaseAccess</title></head><body>");
out.println("<h2>Databaseinfo</h2>");
out.println("<tableborder='1'><tr>");
try{
//loadthedatabasedriver
Class.forName("oracle.jdbc.driver.OracleDriver");
//TheJDBCURLforthisOracledatabase
Stringurl="jdbc:oracle:thin:@192.168.0.2:1521:ORCL";
//Createthejava.sql.Connectiontothedatabase,usingthe
//correctusernameandpassword
conn=DriverManager.getConnection(url,"scott","tiger");
//CreateastatementforexecutingsomeSQL
stmt=conn.createStatement();
//ExecutetheSQLstatement
rs=stmt.executeQuery(sql);
//Getinfoaboutthereturnvalueintheformof
//aResultSetMetaDataobject
rsm=rs.getMetaData();
intcolCount=rsm.getColumnCount();
//printcolumnnamesintableheadercells
for(inti=1;i<=colCount;++i){
out.println("<th>"+rsm.getColumnName(i)+"</th>");
}
out.println("</tr>");
while(rs.next()){
out.println("<tr>");
//printthevaluesforeachcolumn
for(inti=1;i<=colCount;++i)
out.println("<td>"+rs.getString(i)+"</td>");
out.println("</tr>");
}
}catch(Exceptione){
thrownewServletException(e.getMessage());
}finally{
try{
//thiswillcloseanyassociatedResultSets
if(stmt!=null)
stmt.close();
if(conn!=null)
conn.close();
}catch(SQLExceptionsqle){}
}//finally
out.println("</table><br><br>");
out.println("</body>");
out.println("</html>");
}//doGet
}
Herearethestepsneededtorunaservlet,asshowninExample21-1:
1. TaketheJARfilethatcontainsyourdatabasedriver,andstoreiteitherinacommonserverdirectory,suchasTomcat's<Tomcat-root>/common/libdirectoryorintheWEB-INF/libdirectoryofyourwebapplication.
ChangetheextensionoftheOracleJDBCdriver(suchasclasses12.zip)to.jar,sothattheJavaclassesthatitcontainscanbeloadedproperlyintotheJVM.
2. DerivethedatabaseURLfromvendorliterature,andtheusernameandpasswordforthedatabasefromadatabaseadministrator(thatmightbeyou!)orotherappropriatemeans.Thecodewillnotbeabletoaccessthedatabasewithoutavalidusernameandpassword.
Thedownsideofthisapproachisthatyouaremixingupsensitivedatabasesecurityinformationwithservletcode.Itmakesmoresensetoadoptthestrategiesthattheupcomingfiverecipesdescribe,beginningwithRecipe21.2,"ConfiguringaDataSourceinTomcat."
Figure21-1showstheresultofrunningthisservlet.
Figure21-1.Aservletthatdisplayssomedatabaseinformation
Chapter23ontheJSTLshowshowtouseaJSPtoaccessadatabasewithoutaDataSourceconfiguration.
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Recipe21.2-Recipe21.6onconfiguringandusingDataSourcesonTomcatandWebLogic;Recipe21.7andRecipe21.8oncallingstoredproceduresfromservletsandJSPs;Recipe21.9onconvertingajava.sql.ResultSetobjecttoajavax.servlet.jsp.jstl.sqlResult;Recipe21.10andRecipe21.11onusingtransactionsinservletsandJSPs;Recipe21.12onfindingoutinformationaboutaResultSet.
Recipe21.2ConfiguringaDataSourceinTomcat
Problem
Youwanttoconfigureajavax.sql.DataSourceforuseinaservletwiththeTomcatwebcontainer.
Solution
CreatearesourceelementinTomcat'sserver.xmlfileandanassociatedresource-refelementintheweb.xmldeploymentdescriptor.
Discussion
TomcatmakesiteasytosetupaconnectionpoolsothatservletsandJSPscanefficientlysharedatabaseconnections.Inwebsitesthathavemanysimultaneoususers,aconnectionpoolimprovesefficiencybysharingexistingdatabaseconnections,ratherthancreatinganewconnectionandtearingitdowneverytimeanapplicationhastousethedatabase.
AnotherbenefitofconfiguringaconnectionpoolisthatyoucanchangethedatabasesystemthataservletorJSPisusingwithouttouchingtheJavacode,becausethedatabaseresourceisconfiguredoutsideoftheservletorJSP.
HerearethestepsforconfiguringaDataSourcewithTomcat:
1. CreateaResourceandaResourceParamselementinserver.xml,orintheXMLfilethatyouhaveplacedinTomcat's
webappsdirectory.TheseelementsdescribetheJNDIobjectyouarecreatinginordertoprovideyourservletsorJSPswithaDataSource.
Addaresource-refelementtoweb.xml,whichallowsthecomponentsintheassociatedwebapplicationtoaccesstheconfiguredDataSource.
Example21-2showstheResourceandaResourceParamselementsinserver.xml.ThisexampledescribesaDataSourcethatconnectswithanOracle8idatabase.
Example21-2.Theresourceelementinserver.xml
<Resourcename="jdbc/oracle-8i-athletes"scope=
"Shareable"type="javax.sql.DataSource"auth=
"Container"description="HomeOracle8iPersonalEdition"/>
<ResourceParamsname="jdbc/oracle-8i-athletes">
<parameter>
<name>driverClassName</name>
<value>oracle.jdbc.driver.OracleDriver</value>
</parameter>
<parameter>
<name>url</name>
<value>jdbc:oracle:thin:@192.168.0.2:1521:ORCL</value>
</parameter>
<parameter>
<name>username</name>
<value>scott</value>
</parameter>
<parameter>
<name>password</name>
<value>tiger</value>
</parameter>
</ResourceParams>
CreateaResourceandResourceParamselementforeachdatabasethatyourapplicationuses.Example21-3showstheresource-refelementassociatedwiththeResourcespecifiedbyExample21-2.
Example21-3.Aresource-refelementspecifiesaDataSourceinweb.xml
<!--topofweb.xmlfile-->
<resource-ref>
<res-ref-name>jdbc/oracle-8i-athletes</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<!--restofweb.xmlfile-->
TheJNDIpathtothisDataSource,whichyouuseinaJNDIlookup(seethenextrecipe),isjdbc/oracle-8i-athletes.
Theservlet2.4APIdoesnotrequiretheweb.xmlelementssuchasresource-reftoappearinaspecificorder.Theservlet2.3APIspecifiestheordertheseelementsmustappearinwithaDocumentTypeDefinition(DTD).SeeChapter1.
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Recipe21.3onusingaDataSourceinaservletwithTomcat;Recipe21.4-Recipe21.6onconfiguringandusingDataSourceswithservletsandJSPsonWebLogic;Recipe21.7andRecipe21.8oncallingstoredproceduresfromservletsandJSPs;Recipe21.9onconvertingajava.sql.ResultSetobjecttoajavax.servlet.jsp.jstl.sqlResult;Recipe21.10andRecipe21.11onusingtransactionsinservletsandJSPs;Recipe21.12onfindingoutinformationaboutaResultSet.
Recipe21.3UsingaDataSourceinaServletwithTomcat
Problem
YouwanttouseaDataSourcethatyouhaveconfiguredwithTomcat.
Solution
UsetheJNDIAPIclassestoobtaintheDataSource,thenaccessadatabaseconnectionfromthatDataSource.
Discussion
Useclassesfromthejavax.namingpackagetoaccesstheconfiguredDataSource.Forexample,useajavax.naming.InitialContextobjecttolookupaDataSourcethathasbeenboundasaJNDIobject.
Thejavax.namingpackageisapartoftheJavaPlatformStandardEdition1.3and1.4.
Example21-4instantiatesajavax.sql.DataSourceinstancevariableinitsinit()method,whichtheservletcontainercallswhenitcreatesaservletinstance.InTomcat,JNDIobjectsarestoredundertherootlevelspecifiedbythe"java:comp/env"string.
Example21-4.UsingaDataSourceinaservlet
packagecom.jspservletcookbook;
importjava.sql.*;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.sql.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassDbServletextendsHttpServlet{
DataSourcepool;
publicvoidinit()throwsServletException{
Contextenv=null;
try{
env=(Context)newInitialContext().lookup("java:comp/env");
//LookupaDataSource,whichrepresentsaconnectionpool
pool=(DataSource)env.lookup("jdbc/oracle-8i-athletes");
if(pool==null)
thrownewServletException(
"'oracle-8i-athletes'isanunknownDataSource");
}catch(NamingExceptionne){
thrownewServletException(ne.getMessage());
}//try
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
Stringsql="select*fromathlete";
Connectionconn=null;
Statementstmt=null;
ResultSetrs=null;
ResultSetMetaDatarsm=null;
//StartbuildingtheHTMLpage
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>TypicalDatabaseAccess</title></head><body>");
out.println("<h2>Databaseinfo</h2>");
out.println("<tableborder='1'><tr>");
try{
//GetaConnectionfromtheconnectionpool
conn=pool.getConnection();
//CreateaStatementobjectthatcanbeusedtoexecute
//aSQLquery
stmt=conn.createStatement();
//executeasimpleSELECTquery
rs=stmt.executeQuery(sql);
//GettheResultSetMetaDataobjectsowecandynamically
//displaythecolumnnamesintheResultSet
rsm=rs.getMetaData();
intcolCount=rsm.getColumnCount();
//printcolumnnamesintableheadercells
for(inti=1;i<=colCount;++i){
out.println("<th>"+rsm.getColumnName(i)+"</th>");
}
out.println("</tr>");
//whiletheResultSethasmorerows...
while(rs.next()){
out.println("<tr>");
//Printeachcolumnvalueforeachrowwiththe
//ResultSet.getString()method
for(inti=1;i<=colCount;++i)
out.println("<td>"+rs.getString(i)+"</td>");
out.println("</tr>");
}//while
}catch(Exceptione){
thrownewServletException(e.getMessage());
}finally{
try{
//WhenaStatementobjectisclosed,anyassociated
//ResultSetisclosed
if(stmt!=null)
stmt.close();
//VERYIMPORTANT!ThiscodereturnstheConnectiontothe
//pool
if(conn!=null)
conn.close();
}catch(SQLExceptionsqle){}
}
out.println("</table></body></html>");
}//doGet
}
Example21-4getsaDataSourcebyusingtheaddressconfiguredinTomcat(Recipe21.2;jdbc/oracle-8i-athletes)inaJNDIlookup.Thiscodelookslikethis:
env=(Context)newInitialContext().lookup("java:comp/env");
//LookupaDataSource,whichrepresentsaconnectionpool
pool=(DataSource)env.lookup("jdbc/oracle-8i-athletes");
ThecodethenobtainsadatabaseconnectionfromtheconnectionpoolbycallingtheDataSourceobject'sgetConnection()method.ItisveryimportanttocalltheConnectionobject'sclose()methodwhentheservletisfinishedwithit,becausethismethodcallreturnsthesharedConnectiontothepool.
RequestingtheservletofExample21-4inabrowsercreatesoutputthatlooksjustlikeFigure21-1.
Chapter23ontheJSTLshowshowtouseaJSPtoaccessadatabasewithaDataSourceconfiguration.
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Recipe21.1onaccessingadatabasefromaservletwithoutaconnectionpool;Recipe21.2onconfiguringaDataSourceonTomcat;Recipe21.4-Recipe21.6onconfiguringandusingDataSourcewithservletsandJSPsonWebLogic;Recipe21.7andRecipe21.8oncallingstoredproceduresfromservletsandJSPs;Recipe21.9onconvertingajava.sql.ResultSetobjecttoajavax.servlet.jsp.jstl.sqlResult;Recipe21.10andRecipe21.11onusingtransactionsinservletsandJSPs;Recipe21.12onfindingoutinformationaboutaResultSet.
Recipe21.4CreatingaDataSourceonWebLogic
Problem
Youwanttocreateajavax.sql.DataSourceonBEAWebLogicforuseinyourservlets.
Solution
UsetheWebLogicconsoletoconfigureanewconnectionpool,thenconfigureanewDataSourceassociatedwiththatpool.
Discussion
ConfiguringaWebLogicDataSourceinvolvesthefollowingsteps:
1. LogintotheWebLogicconsole,whichallowsyoutomanagetheWebLogicserverfromabrowser.TheURLfortheconsoleistypicallyhttp://<localhost:7001>/console(substituteyourhostnamefor"localhost"andtheportnumberthatmatchesyourownWebLogicconfiguration).
ClickonYour-domain-name Services JDBC ConnnectionPoolsonthemenutreeintheconsole'slefthandcolumn.Thenclickon"ConfigureanewJDBCConnectionPool...".
Intheresultingwindow,enteranamefortheconnectionpool,theJDBCURL(e.g.,jdbc:oracle:thin:@192.168.0.2:1521:ORCL),theDriverclassname(e.g.,oracle.jdbc.driver.OracleDriver),aswellastheusernameandpasswordinthe"Properties"textfield.Figure
21-2showsaconfiguredconnectionpoolnamed"OraclePool."Rememberthisnameyou'llneedittoconfigureaDataSourcefurtheralongintheprocess.
Figure21-2.CreatingaconnectionpoolwiththeWebLogicconsoleapplication
4. Clickonthe"Create"buttoninthiswindowtocreatetheconnectionpool,thenchoosethe"Targets"tab.Theresultingscreenallowsyoutochooseaservertowhichtheconnectionpoolwillapply.Afteryouhavechosentheserver,clickonthe"Apply"buttonintheTargetsscreen.Thenameofthenewpoolshouldappearinthelefthandmenuframe.
ClickonYour-domain-name Services JDBC DataSourcesandclickontheURL"ConfigureaNewJDBCDataSource...".Figure21-3showsaDataSourceconfigurationwindowthatincludestheDataSourcename("oracle-8i-athletes")underwhichWebLogicwillbindtheDataSourceasaJNDIobject.Thewindowalsohasatextfieldwhereyoumustenterthenameoftheconnectionpoolthatyoujustconfigured:"OraclePool."Clickthe"Create"buttontocreatethenew
DataSource.Figure21-3showstheJDBCDataSourceswindow.
Takethesamestepsasinstep4withthe"Targets"screentoapplythisDataSourcetotheappropriateserver.Painless,right?
Figure21-3.CreatingaDataSourcewiththeWebLogicconsoleapplication
Figure21-4showstheWebLogicJNDItreewheretheDataSourcethatyouhavejustcreatedisbound.
Figure21-4.AviewoftheWebLogicJNDItreecontainingtheDataSource
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Chapter2ondeployingservletsandJSPsonWebLogic;Recipe21.2andRecipe21.3onusingaDataSourceonTomcat;Recipe21.5andRecipe21.6onusingDataSourceswithservletsandJSPsonWebLogic.
Recipe21.5UsingaJNDILookuptogetaDataSourcefromWebLogic
Problem
YouwanttouseaJNDIlookuptoaccessaWebLogicDataSource.
Solution
UsetheJNDIAPIandtheclassesinthejavax.namingpackagetogettheJNDIobjectthatyouhaveboundonWebLogic.
Discussion
AccessingaConnectionfromaWebLogicDataSourceandconnectionpoolusessimilarJavacodecomparedwithTomcat.
1. SetuptheconnectionpoolandDataSourcebyfollowingRecipe21.4sinstructions.
Intheservletcode,gettheDataSourcebyusingaJNDIlookup.Thisinvolvescreatinganinstanceofajavax.naming.InitialContextandthencallingitslookup()methodwiththenamethatyougaveyourDataSource(Recipe21.4).
GetaConnectionfromtheDataSourcebycallingtheDataSource'sgetConnection()method.
Example21-5createsaninstanceofanInitialContextbypassinginaHashtablethatcontainssomepropertyvalues.
Example21-5.AservletthatusesaWebLogicconnectionpool
packagecom.jspservletcookbook;
importjava.util.Hashtable;
importjava.sql.*;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.sql.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassWeblogicDbServletextendsHttpServlet{
DataSourcepool;
publicvoidinit()throwsServletException{
Contextenv=null;
Hashtableht=newHashtable();
//Createpropertynames/valuesthatwillbepassedto
//theInitialContextconstructor
ht.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
//t3://localhost:7001isthedefaultvalue
//Addyourownvalueifnecessary:
//ht.put(Context.PROVIDER_URL,"t3://localhost:7001");
try{
env=newInitialContext(ht);
pool=(javax.sql.DataSource)env.lookup(
"oracle-8i-athletes");
if(pool==null)
thrownewServletException(
"'oracle-8i-athletes'isanunknownDataSource");
}catch(NamingExceptionne){
thrownewServletException(ne);
}
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
Stringsql="select*fromathlete";
Connectionconn=null;
Statementstmt=null;
ResultSetrs=null;
ResultSetMetaDatarsm=null;
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>WeblogicDatabaseAccess</title></head><body>");
out.println("<h2>Databaseinfo</h2>");
out.println("<tableborder='1'><tr>");
try{
conn=pool.getConnection();
stmt=conn.createStatement();
rs=stmt.executeQuery(sql);
rsm=rs.getMetaData();
intcolCount=rsm.getColumnCount();
//printcolumnnames
for(inti=1;i<=colCount;++i){
out.println("<th>"+rsm.getColumnName(i)+"</th>");
}
out.println("</tr>");
while(rs.next()){
out.println("<tr>");
for(inti=1;i<=colCount;++i)
out.println("<td>"+rs.getString(i)+"</td>");
out.println("</tr>");
}
}catch(Exceptione){
thrownewServletException(e.getMessage());
}finally{
try{
if(stmt!=null)
stmt.close();
//RETURNTHECONNECTIONTOTHEPOOL!
if(conn!=null)
conn.close();
}catch(SQLExceptionsqle){}
}
out.println("</table></body></html>");
}//doGet
}
OnceyouhaveaccessedaConnectionfromtheWebLogicconnectionpool,thecodecanexecutevariousSQLstatementsinordertointeractwiththeassociateddatabase.AlwayscalltheConnection'sclose()methodwhenyouarefinishedwiththeConnection,becausethismethodcallreturnsthesharedConnectiontothepool.
Example21-5cannotworkwithoutaproperlyconfiguredconnectionpoolandDataSource,whichisveryeasytodowiththeWebLogicconsole(asexplainedinRecipe21.4).
TheservletoutputlooksjustlikeFigure21-1,exceptforthedifferentURLinthewebbrowser'saddressfield(http://localhost:7001/dbServlet).
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Recipe21.1onaccessingadatabasefromaservletwithoutaconnectionpool;Recipe21.2andRecipe21.3onusingaDataSourceonTomcat;Recipe21.6onusingaDataSourcewithaJSPonWebLogic;Recipe21.7andRecipe21.8oncallingstoredproceduresfromservletsandJSPs;Recipe21.9onconvertingajava.sql.ResultSetobjecttoajavax.servlet.jsp.jstl.sqlResult;Recipe21.10andRecipe21.11onusingtransactionsinservletsandJSPs;Recipe21.12onfindingoutinformationaboutaResultSet.
Recipe21.6UsingaDataSourcefromWebLogicinaJSP
Problem
Youwanttousethejavax.sql.DataSourcethatyousetuponWebLogicinaJSP.
Solution
UseJSPscriptletstoaccesstheDataSourcewithaJNDIlookup,thenusetheJDBCAPIinthescriptletstoaccessthedatabase.
Discussion
TheJSPinExample21-6transplantscodefromaservletinsideofHTMLtemplatetext.TheJSPusesscriptlets,whichcontainJavacodewithin"<%%>"characters.
JSTLSQLtagsarepreferabletoscriptletsinaJSP;however,theJSTLimplementationIuseforthisbook'sexamplescannotaccessaDataSourcefromWebLogic'sJNDIimplementation.SeeRecipe23.6foranexamplethatusestheJSTLSQLtagswithaTomcatDataSource.
Example21-6importsthenecessaryclassesatthetopofthecodeusingthepagedirectiveanditsimportattribute.Otherwise,thisJSPaccomplisheseverythingthattheservletofthepriorrecipedoes,
includingthedisplayofnearlyidenticaloutputinthewebbrowser(seeFigure21-1inRecipe21.1).
Example21-6.UsingaJSPscriptlettoaccessaWebLogicDataSource
<%@pageimport="java.util.Hashtable,java.sql.*,javax.naming.*,javax.sql.*"%>
<html>
<head><title>DatabaseQueryinWebLogic</title></head>
<body>
<h2>QueryingadatabasewithaJSPinWebLogic</h2>
<%
Contextenv=null;
DataSourcepool=null;
Hashtableht=newHashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL,"t3://localhost:7001");
env=newInitialContext(ht);
//LookupthisDataSouceatthetopleveloftheWebLogicJNDItree
pool=(DataSource)env.lookup("oracle-8i-athletes");
Stringsql="select*fromathlete";
Connectionconn=null;
Statementstmt=null;
ResultSetrs=null;
ResultSetMetaDatarsm=null;%>
<tableborder='1'><tr>
<%
try{
//getajava.sql.Connectionfromthepool
conn=pool.getConnection();
stmt=conn.createStatement();//createajava.sql.Statement
//executeaSQLstatement,generatingaResultSet
rs=stmt.executeQuery(sql);
rsm=rs.getMetaData();
intcolCount=rsm.getColumnCount();
//printcolumnnames
for(inti=1;i<=colCount;++i){%>
<th><%=rsm.getColumnName(i)%></th>
<%}%>
</tr>
<%while(rs.next()){%>
<tr>
<%for(inti=1;i<=colCount;++i){%>
<td><%=rs.getString(i)%></td>
<%}//for%>
</tr>
<%}//while
}catch(Exceptione){
thrownewJspException(e.getMessage());
}finally{
try{
stmt.close();
conn.close();
}catch(SQLExceptionsqle){}
}%>
</body>
</html>
AftermakingsurethatyouhaveproperlyconfiguredtheconnectionpoolandDataSourceintheWebLogicconsole,viewthisJSP'soutputbycopyingittoWebLogic'sdefaultwebapplication,thenrequestaURLinyourbrowserthatlookslikethisone:http://localhost:7001/sqlWeblogic.jsp.
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Chapter2ondeployingservletsandJSPsonWebLogic;Recipe21.1onaccessingadatabasefromaservletwithoutaconnectionpool;Recipe21.2andRecipe21.3onusingaDataSourceonTomcat;Recipe21.4andRecipe21.5onusingDataSourceswithservletsonWebLogic;Recipe21.7andRecipe21.8oncallingstoredproceduresfromservletsandJSPs;Recipe21.9onconvertingajava.sql.ResultSetobjecttoajavax.servlet.jsp.jstl.sqlResult;Recipe21.10andRecipe21.11onusingtransactionsinservletsandJSPs;Recipe21.12on
findingoutinformationaboutaResultSet.
Recipe21.7CallingaStoredProcedurefromaServlet
Problem
Youwanttocallastoredprocedurefromaservlet.
Solution
Usethejava.sql.CallableStatementclassinsideaservletservicemethod,suchasdoGet()ordoPost().
Discussion
DatabasedeveloperscreatestoredprocedurestypicallyforSQLcodethattheywanttoexecuteonaregularbasis,similartoaJavadeveloper'sreasonforcreatingamethod.AstoredprocedureisapieceofSQLthatthedatabasesystempre-compilesunderaspecificname.ThestoredprocedurethatIuseinthisrecipeisnamedaddEvent.
Naturally,awebdeveloperwhoisusingadatabasewillwanttocallthesestoredprocedures.Thejava.sql.CallableStatementclassencapsulatesaparticularstoredprocedure,sothatyoucanusethesetoolswithinJDBCcode.
Table21-1showsthetableschemaforthetablethataddEventuses.Thetablehasfourcolumns:EVENT_ID,NAME,LOCATION,andRACEDATE.
Table21-1.TheRACEEVENTdatabasetableschema
Name Null? Type
EVENT_ID NOTNULL NUMBER
NAME NOTNULL VARCHAR2(30)
LOCATION NOTNULL VARCHAR2(30)
RACEDATE DATE
Example21-7showstheaddEventdefinitionusingOracle8i'ssyntax.Thisstoredproceduretakesaneventname,location,anddateasarguments.IttheninsertsthesevaluesintoanewrowintheRACEEVENTtable.
Apieceofcodecalledasequencenamedlog_seqprovidesthevalueforthenewrow'sEVENT_IDcolumn.InOracle'sdatabasesystem,asequencecankeeptrackofalongsequenceofnumbers.Thedatabasedevelopercreatesthesequence,justastheywouldcreateastoredprocedure.
Example21-7.ASQLstoredproceduredesignedtoaddarowtotheEVENTtable
createorreplaceprocedureaddEvent(eventnameinvarchar2,
location_invarchar2,date_indate)
as--needtodoinsertsinraceevent
begin
insertintoraceeventvalues(log_seq.nextval,
eventname,location_,date_);
end;
/
Ifyou'reusingadatabasetoolsuchasSQLPLUSfromthecommandline,calltheaddEventprocedureinthefollowingmanner:
execaddEvent('FalmouthTriathlon','FalmouthMA','26-Jul-2003');
Example21-8showshowyoucancalladdEventinaservlet.ThefollowingservletcallsthestoredprocedurefromdoGet()initsownaddRaceEventmethod.Thismethodhasajava.util.Listasanargument.TheListcontainsthevaluesthatthecodeusesasargumentstocalltheaddEventstoredprocedure.
Example21-8.AservletusesCallableStatementtocallthestoredprocedure
packagecom.jspservletcookbook;
importjava.sql.*;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.Iterator;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.sql.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassStoredProcServletextendsHttpServlet{
DataSourcepool;
publicvoidinit()throwsServletException{
Contextenv=null;
try{
env=(Context)newInitialContext().lookup("java:comp/env");
pool=(DataSource)env.lookup("jdbc/oracle-8i-athletes");
if(pool==null)
thrownewServletException(
"'oracle-8i-athletes'isanunknownDataSource");
}catch(NamingExceptionne){
thrownewServletException(ne);
}
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
StringeventName=request.getParameter("eName");
Stringlocation=request.getParameter("eLocation");
Stringdate=request.getParameter("eDate");
ListparamList=newArrayList();
paramList.add(eventName);
paramList.add(location);
paramList.add(date);
try{
addRaceEvent(paramList);
}catch(SQLExceptionsqle){
thrownewServletException(sqle.getMessage());
}//try
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head><title>AddanEvent</title></head><body>");
out.println(
"<h2>TheEventnamed"+eventName+
"hasbeenaddedtothedatabase</h2>");
out.println("</body>");
out.println("</html>");
}//doGet
publicConnectiongetConnection(){
Connectionconn=null;
try{
conn=pool.getConnection();
}catch(SQLExceptionsqle){
thrownewServletException(sqle.getMessage());
}finally{
returnconn;
}
}
publicvoidaddRaceEvent(Listvalues)throwsSQLException{
if(values==null)
thrownewSQLException(
"InvalidparameterinaddRaceEventmethod.");
Connectionconn=null;
conn=getConnection();
if(conn==null)
thrownewSQLException(
"InvalidConnectioninaddRaceEventmethod");
Iteratorit=values.iterator();
CallableStatementcs=null;
//CreateaninstanceoftheCallableStatement
cs=conn.prepareCall("{calladdEvent(?,?,?)}");
for(inti=1;i<=values.size();i++)
cs.setString(i,(String)it.next());
//CalltheinheritedPreparedStatement.executeUpdate()method
cs.executeUpdate();
//returntheconnectiontothepool
conn.close();
}//addRaceEvent
}
Example21-8getsaConnectionfromaconnectionpoolusingthetechniquesexplainedinthepriorrecipes.ThecodeusestheConnectiontocreateaCallableStatementthattheexamplecanusetocalltheunderlyingstoredprocedure:
cs=conn.prepareCall("{calladdEvent(?,?,?)}");
TheStringargumenttotheConnection'sprepareCallmethodcontainsquestionmarks(?)asplaceholdersforthestoredprocedure'sparameters.ThecodethencallstheCallableStatement'ssetString()methodtogivetheseplaceholdersvalues.Finally,thecodecallstheCallableStatement'sexecuteUpdate()methodtoexecuteaddEvent.
Ifcallingthestoredprocedurecausesadatabaseerror,theaddRaceEventmethodthrowsaSQLException.
Theservletreceivesvaluesforthenewrowfromrequestparameters.ThefollowingURLcallstheservletwiththreeparameters:eName,eLocation,andeDate:
http://localhost:8080/home/servlet/com.jspservletcookbook.
StoredProcServlet?eName=
Falmouth%20Triathlon&eLocation=Falmouth%20MA&eDate=26-July-2003
Figure21-5showstheservlet'soutputinawebbrowser.
Figure21-5.ThebrowseroutputoftheStoredProcServlet
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Recipe21.1onaccessingadatabasefromaservletwithoutaconnectionpool;Recipe21.2andRecipe21.3onusingaDataSourceonTomcat;Recipe21.4-Recipe21.6onusingDataSourceswithservletsandJSPsonWebLogic;Recipe21.8oncallingastoredprocedurefromaJSP;Recipe21.9onconvertingajava.sql.ResultSetobjecttoajavax.servlet.jsp.jstl.sqlResult;Recipe21.10andRecipe21.11onusingtransactionsinservletsandJSPs;Recipe21.12onfindingoutinformationaboutaResultSet.
Recipe21.8CallingaStoredProcedurefromaJSP
Problem
YouwanttocallastoredprocedurefromaJSP.
Solution
UsingaJSP2.0container,developanExpressionLanguage(EL)functionthatwillcallthestoredprocedureforyou.
Discussion
JSP2.0introducedfunctions,whicharestaticmethodsthatyoucancallinsideELstatements.
SeeChapter23ifyouneedtofamiliarizeyourselfwiththeEL.
Thisrecipeexplainsthestepsfordevelopingafunctionthatcallsastoredprocedure:
1. Createthestoredprocedureinyourdatabasesystem.
WritetheJavaclassthatimplementsthefunctionasastaticorclassmethod.
DefinethefunctioninaTagLibraryDescriptor(TLD),whichisanXMLconfigurationfilethatyouincudewiththewebapplication.
IntheJSPitself,usethetaglibdirectivetodeclarethetaglibrarythatcontainsthefunction.
CallthefunctionintheJSP,usingtheproperprefixforyourtaglibrary.ThefunctionIuseinthisrecipelookslikethis:
<cbck:addRaceEvent("MyRace","AnytownUSA","11-Dec-2003")/>
Example21-9showstheJavaclassthatimplementsthisfunction.
Example21-9.TheJavaclassthatimplementsanELfunction
packagecom.jspservletcookbook;
importjava.sql.*;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.sql.*;
publicclassStoredProcUtil{
privatestaticDataSourcepool;
privatestaticContextenv;
static{//staticinitializationoftheContextandDataSource
try{
env=(Context)newInitialContext().lookup("java:comp/env");
pool=(DataSource)env.lookup("jdbc/oracle-8i-athletes");
if(pool==null)
thrownewException(
"'oracle-8i-athletes'isanunknownDataSource");
}catch(Exceptione){
System.out.println(e);
}
}//static
/*ThisstaticmethodwillbeconfiguredinaTLDfileandprovidethe
implementationforanELfunction.Anexampleuseofthefunctionis:
<cbck:addRaceEvent("MyRace","AnytownUSA","11-Dec-2003")/>*/
publicstaticvoidaddRaceEvent(Stringname,Stringlocation,Stringdate){
if((!check(name))||(!check(location))||(!check(date)))
thrownewIllegalArgumentException(
"InvalidparamvaluespassedtoaddRaceEvent()");
Connectionconn=null;
try{
conn=pool.getConnection();
if(conn==null)
thrownewSQLException(
"InvalidConnectioninaddRaceEventmethod");
CallableStatementcs=null;
//CreateaninstanceoftheCallableStatement
cs=conn.prepareCall("{calladdEvent(?,?,?)}");
cs.setString(1,name);
cs.setString(2,location);
cs.setString(3,date);
//CalltheinheritedPreparedStatement.executeUpdate()method
cs.executeUpdate();
//returntheconnectiontothepool
conn.close();
}catch(SQLExceptionsqle){}
}//addRaceEvent
privatestaticbooleancheck(Stringvalue){
if(value==null||value.equals(""))
returnfalse;
returntrue;
}
}
TheaddRaceEvent()methodcreatesajava.sql.CallableStatement,whichcallstheunderlyingstoredprocedure(addEvent).Recipe21.7explainsthisprocess.
TheJavamethodthatimplementsthefunctionforaJSPmustbedefinedasstatic.
ThisJavaclassmustbestoredinyourwebapplicationbeneaththeWEB-INF/classesdirectory(withasubdirectorystructurematchingitspackagename)orinaJARfilestoredinWEB-INF/lib.Forexample,theJavaclassofExample21-9shouldbestoredinWEB-INF/classes/com/jspservletcookbook/StoredProcUtil.class.
Example21-10showstheTLDfilethatdefinestheELfunction.
TheTLDfilehasa.tldextensionandlivesinaWEB-INFsubdirectoryofyourwebapplication,suchasWEB-INF/tlds.
Example21-10.TheTLDfileforconfiguringtheELfunction
<taglibxmlns="http://java.sun.com/xml/ns/j2ee"xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation=
"http://java.sun.com/xml/ns/j2eehttp://java.sun.com/xml/ns/j2ee/
web-jsptaglibrary_2_0.xsd"
version="2.0"
>
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>cbck</short-name>
<uri>jspservletcookbook.com.tags</uri>
<description>Cookbookcustomtags</description>
<function>
<name>addRaceEvent</name>
<function-class>
com.jspservletcookbook.StoredProcUtil
</function-class>
<function-signature>
voidaddRaceEvent(java.lang.String,
java.lang.String,java.lang.String)
</function-signature>
</function>
<tag>
<!--defineacustomtaghereifyouhaveto-->
</tag>
</taglib>
Example21-10definesthefunctionwiththefunctiontaganditsname,function-class,andfunction-signatureattributes.Makesuretoincludethefullyqualifiedclassnameunderfunction-class.TheJSPcontainerknowshowtocallthefunctionbyinspectingthefunction-signature.Thissignatureincludesthereturntype("void"inthiscase),thefunctionname,andallofitsparametersspecifiedbytheirfullyqualifiedclassnames.
Example21-11isaJSPthatcallsourdefinedfunction.First,thetaglibdirectivedeclaresthetaglibraryandprefix("cbck")thatthefunctionuses.
Example21-11.AJSPusesanELfunctiontocallastoredprocedure
<%@tagliburi="jspservletcookbook.com.tags"prefix="cbck"%>
<html>
<head><title>CallingaStoredprocedure</title></head>
<body>
<h2>ThisJSPcallsastoredprocedurewithaJSP2.0function</h2>
${cbck:addRaceEvent("FalmouthTriathlon","FalmouthMA","26-Jul-2003")}
</body>
</html>
SincethisisafeatureoftheEL,thesyntaxencapsulatesthefunctioncallwithinthe"${}"characterstring.Nextcomestheprefix(cbck),acolon,andthefunctioncallitself:
${cbck:addRaceEvent("FalmouthTriathlon","FalmouthMA","26-Jul-2003")}
Thisprocessappearscomplicatedthefirsttimearound,butonceyoucreateyourfirstJSP2.0function,therestofthemwillbemucheasier!ThisfeaturedoesnotinvolvemuchmorethancreatingastaticJavamethod,configuringthefunctionwiththepropervaluesinanXMLfile,thencallingthefunctioninaJSP.Thisisaniftywaytocallstoredprocedures!
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Chapter23ontheJSTL;Chapter22oncreatingcustomtaglibraries;Recipe21.1onaccessingadatabasefromaservletwithoutaconnectionpool;Recipe21.2andRecipe21.3onusingaDataSourceonTomcat;Recipe21.5andRecipe21.6onusingDataSourceswithservletsandJSPsonWebLogic;Recipe21.7oncallingastoredprocedurefromaservlet;Recipe21.9onconvertingajava.sql.ResultSetobjecttoajavax.servlet.jsp.jstl.sql.Result;Recipe21.10andRecipe21.11onusingtransactionsinservletsandJSPs;Recipe21.12onfindingoutinformationaboutaResultSet.
Recipe21.9ConvertingaResultSettoaResultObject
Problem
Youwanttoconvertajava.sql.ResultSettoajavax.servlet.jsp.jstl.sql.ResultobjectsothattheobjectcanbeusedwiththeJSTL.
Solution
Usethejavax.servlet.jsp.jstl.sql.ResultSupport.toResult()
method.
Discussion
TheResultinterfaceallowscodetoworkwithResultSetsintheformofJavaarraysorjava.util.Maps.TheJSTLtagsoftenusearraysorMapstoiteratethroughvalues(whichiswhytheyincludedtheResultinterfaceintheJSTLspecification).Therefore,youmightwanttoconvertaResultSettoaResult,thenhandtheResulttoaJSPthatusestheJSTLtags.
Example21-12isaservletthat:
1. CreatesaResultSetbyqueryingadatabase.
ConvertstheResultSettoaResult.
ForwardstheResulttoaJSPbystoringtheResultasasessionattribute.
Example21-12.AservletconvertsaResultSettoaResult
packagecom.jspservletcookbook;
importjava.sql.*;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.sql.*;
importjavax.servlet.jsp.jstl.sql.Result;
importjavax.servlet.jsp.jstl.sql.ResultSupport;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassDbServletResultextendsHttpServlet{
DataSourcepool;
publicvoidinit()throwsServletException{
Contextenv=null;
try{
env=(Context)newInitialContext().lookup("java:comp/env");
pool=(DataSource)env.lookup("jdbc/oracle-8i-athletes");
if(pool==null)
thrownewServletException(
"'oracle-8i-athletes'isanunknownDataSource");
}catch(NamingExceptionne){
thrownewServletException(ne);
}
}//init
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
Stringsql="select*fromathlete";
try{
//GetaResultobjectthatrepresentsthereturnvalueoftheSQL
//statement'select*fromathlete'
ResultjspResult=select(sql);
HttpSessionsession=request.getSession();
//storetheResultinasessionattribute,
//whereitcanbepassedto
//aJSPandusedwiththeJSTLtags
session.setAttribute(
"javax.servlet.jsp.jstl.sql.Result",jspResult);
RequestDispatcherdispatcher=request.getRequestDispatcher(
"/useResult.jsp");
dispatcher.forward(request,response);
}catch(SQLExceptionsqle){
thrownewServletException(sqle.getMessage());}
}//doGet
privateResultselect(Stringsql)throwsSQLException{
if(sql==null||sql.equals(""))
thrownewSQLException("Invalidparameterinselectmethod");
ResultSetrs=null;
Connectionconn=null;
Resultres=null;
//GetaConnectionfromthepool
conn=pool.getConnection();
if(conn==null)
thrownewSQLException("InvalidConnectioninselectmethod");
PreparedStatementstmt=conn.prepareStatement(sql);
//CreatetheResultSet
rs=stmt.executeQuery();
//ConverttheResultSettoa
//ResultobjectthatcanbeusedwithJSTLtags
res=ResultSupport.toResult(rs);
stmt.close();//thiswillcloseanyassociatedResultSets
conn.close();//returnConnectiontopool
returnres;//returnResultobject
}//select
}
Example21-12importsthenecessaryJavaclassesincludingtheResultandResultSupportclasses:
importjavax.servlet.jsp.jstl.sql.Result;
importjavax.servlet.jsp.jstl.sql.ResultSupport;
Theselect()methoddoestheimportantwork:creatingtheResultSet,convertingthisobjecttoaResult,andreturningtheResult.Hereisthecodethatperformstheconversion:
res=ResultSupport.toResult(rs);
TheResultSupportclass'sstatictoResult()methodtakesaResultSetasanargumentandreturnsaResult.
Theservlet'sdoGet()methodthencreatesasessionattributefromtheResultandusesaRequestDispatchertoforwardtherequesttoaJSP.TheJSPisnameduseResult.jsp.
Theuserinitiallyrequeststheservletinhisbrowser,andtheservletpassestherequesttotheJSP.TheuserthenseestheJSP'soutputintheirbrowser.
TheRequestDispatchercodelookslikethis:
RequestDispatcherdispatcher=request.getRequestDispatcher(
"/useResult.jsp");
dispatcher.forward(request,response);
Example21-13usestheJSTLcoretags(withthe"c"prefix).Thec:settaggainsaccesstothesessionattributeandstorestheattribute'svalueinaresultObjvariable.Thec:forEachandc:outtagsthendisplay
thedatabasevaluesintheJSP.
Example21-13.TheJSPthatusesaResultobjectstoredasasessionattribute
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%@tagliburi="http://java.sun.com/jstl/sql"prefix="sql"%>
<html>
<HEAD>
<TITLE>UsingaResultobject</TITLE>
</HEAD>
<bodybgcolor="white">
<h2>ViewDatabaseData</h2>
<%--storeasessionattribute(theResultobject)inavariablenamed'resultObj'--%>
<c:setvar="resultObj"value=
"${sessionScope[\"javax.servlet.jsp.jstl.sql.Result\"]}"/>
<tableborder="1"cellspacing="2">
<%--foreveryrowintheResult...--%>
<c:forEachitems="${resultObj.rows}"var="row">
<%--foreverycolumnintherow...--%>
<c:forEachitems="${row}"var="column">
<tr>
<tdalign="right">
<b><c:outvalue="${column.key}"/></b>
</td>
<td>
<c:outvalue="${column.value}"/>
</td></tr>
</c:forEach>
</c:forEach>
</table>
</body>
</html>
Thesyntax"${sessionScope[\"javax.servlet.jsp.jstl.sql.Result\"]}"isnecessary,becausethesessionattributenamecontainsperiods(.).Otherwise,theELcanacccessascopedattribute,iftheattributeisnamedmyAttribute,usingthissimplersyntax:
${myAttribute}
Figure21-6showshowawebbrowserdisplaystheJSP'soutput.
Figure21-6.TheJSPpageoutputinawebbrowser
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Chapter23ontheJSTL;Chapter16onusingsessionattributes;Recipe21.1onaccessing
adatabasefromaservletwithoutaconnectionpool;Recipe21.2andRecipe21.3onusingaDataSourceonTomcat;Recipe21.5andRecipe21.6onusingDataSourceswithservletsandJSPsonWebLogic;Recipe21.7andRecipe21.8oncallingstoredproceduresfromservletsandJSPs;Recipe21.10andRecipe21.11onusingtransactionsinservletsandJSPs;Recipe21.12onfindingoutinformationaboutaResultSet.
Recipe21.10ExecutingSeveralSQLStatementsWithinaSingleTransaction
Problem
YouwanttoexecutemorethanoneSQLstatementwithinasingletransaction.
Solution
Usethejava.sql.ConnectionAPIandthesetAutoCommit(),commit(),androllback()methodstocreateatransaction.
Discussion
SomeSQLstatements,suchasthosethatupdatecustomerinformationintwodifferentdatabasetables,aremeanttobeexecutedonlyasagroup.Ifoneofthemdoesnotsucceed,thedatabaseisreturnedtoitspreviousstate.ThisisthepurposeofusingatransactioninyourJavacode.Atransactionisalogicalunitofdatabaseoperationsthatcanbe"rolledback"orcanceledasagroupifsomethinggoeswrongwithoneoftheoperations.
Onceyouhaveadatabaseconnection(aninstanceofjava.sql.Connection),youcancallvariousConnectionmethodstocreateatransaction.Herearethestepsforexecutingatransaction:
1. CalltheConnectionobject'ssetAutoCommit()methodwithfalseastheparameter.ThisturnsoffthedefaultbehaviorforJDBCcode,whichistocommiteachseparateSQLstatement
insteadofautomaticallygroupingsequentialstatementsasasingletransaction.
FollowthesetAutoCommit()methodcallwiththedatabasecodethatyouwanttotreatasasingletransaction.
CalltheConnection'scommit()methodtocommittheSQLstatements,whichwritesanydatabasechangesassociatedwiththeSQL(suchasaDELETEorUPDATEstatement)totheunderlyingdatabasefile.
IntheareaofJavacodereservedfordealingwitherrorsorunexpectedconditions,suchasacatchblock,calltheConnection'srollback()method,whichrollsbacktheSQLthatwasincludedinthetransaction.
Example21-14isaservletthatillustratesthisprocess.
Example21-14.AservletthatusesaSQLtransaction
packagecom.jspservletcookbook;
importjava.sql.*;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.sql.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassDbServletTransextendsHttpServlet{
DataSourcepool;
/*InitializetheDataSourceintheservlet'sinit()method
whichtheservletcontainercallsoncewhenitcreatesaninstanceof
theservlet*/
publicvoidinit()throwsServletException{
Contextenv=null;
try{
env=(Context)newInitialContext().lookup("java:comp/env");
pool=(DataSource)env.lookup("jdbc/oracle-8i-athletes");
if(pool==null)
thrownewServletException(
"'oracle-8i-athletes'isanunknownDataSource");
}catch(NamingExceptionne){
thrownewServletException(ne);
}
}//init
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
Connectionconn=null;
Statementstmt=null;
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Usingtransactions</title></head><body>");
out.println(
"<h2>TheseSQLstatementsarepartofatransaction</h2>");
out.println("CallableStatement.executeUpdate()");
out.println("<br><br>");
out.println("Statement.executeUpdate()");
out.println("<br><br>");
try{
//Getaconnectionfromthepool
conn=pool.getConnection();
//DisplaythedefaultvaluesforsetAutoCommit()
//andtheisolationlevel
out.println("AutoCommitbeforesetAutoCommit():"+
conn.getAutoCommit()+"<br><br>");
out.println("Transactionisolationlevel:");
//justoutofcuriosity,displaytheexistingtransaction
//isolationlevel
witch(conn.getTransactionIsolation()){
case0:out.println("TRANSACTION_NONE<br><br>");break;
case1:out.println(
"TRANSACTION_READ_UNCOMMITTED<br><br>");break;
case2:out.println(
"TRANSACTION_READ_COMMITTED<br><br>");break;
case4:out.println(
"TRANSACTION_REPEATABLE_READ<br><br>");break;
case8:out.println(
"TRANSACTION_SERIALIZABLE<br><br>");break;
default:out.println("UNKNOWN<br><br>");
}//switch
//setAutocommittofalsesothatindividualSQLstatementswill
//notbecommitteduntilConnection.commit()iscalled
conn.setAutoCommit(false);
//Transaction-relatedSQLbegins...
CallableStatementcs=null;
//CreateaninstanceoftheCallableStatement
cs=conn.prepareCall("{calladdEvent(?,?,?)}");
cs.setString(1,"SalisburyBeach5-Miler");
cs.setString(2,"SalisburyMA");
cs.setString(3,"14-Aug-2003");
//CalltheinheritedPreparedStatement.executeUpdate()method
cs.executeUpdate();
Stringsql="updateraceeventsetracedate='13-Aug-2003'"+
"wherename='SalisburyBeach5-Miler'";
intres=0;
stmt=conn.createStatement();
res=stmt.executeUpdate(sql);
//committhetwoSQLstatements
conn.commit();
}catch(Exceptione){
try{
//rollbackthetransactionincaseofaproblem
conn.rollback();
}catch(SQLExceptionsqle){}
thrownewServletException(e.getMessage());
}finally{
try{
if(stmt!=null)
stmt.close();
if(conn!=null)
conn.close();
}catch(SQLExceptionsqle){}
}
out.println("</table></body></html>");
}//doGet
}
ThedoGet()methodinExample21-14displaysthedefaultvaluesfor"autocommitting"SQLstatementsandthetransactionisolationlevel(thelevelofdatabase-lockingthatoccursasthetransactionswithinyourJavacodeareinitiated).Forexample,ifyourSQLstatementsincludetheupdatingofdatabasefields,canotherusersofthedatabaseviewthenewcolumnvaluesbeforeyourtransactioniscommitted?Ifallowed,this
typeofbehavioriscalledadirtyread.
Table21-2showsthedifferenttypesoftransactionisolationlevels,fromtheleasttomostrestrictivelevel.Twoothertermsneedaddressingbeforeyouinspectthistable:
Anon-repeatablereadoccurswhenonetransactionreadsarow,anothertransactionchangesthesamerow,andthefirsttransactionreadsthesamerowandreceivesthedifferentvalue.
AphantomreadhappenswhenonetransactionobtainsaresultsetbasedonaWHEREconditionandasecondtransactioninsertsanewrowthatsatisfiesthisWHEREcondition.ThefirsttransactionthenevaluatesthesamedatabasetableagainwiththesameWHEREconditionandretrievesthenew"phantom"row.
Table21-2.Transactionisolationlevels
Transactionisolationlevel
Returnvalueofjava.sql.Connection.
getTransactionIsolation()Definition
TRANSACTION_NONE 0 Thedatabasedriverdoesnotsupporttransactions.
TRANSACTION_READ_
UNCOMMITTED1 Anothertransactioncanseeuncommittedchanges;
"dirtyreads"areallowed.
TRANSACTION_READ_
COMMITTED2 Uncommittedchangesarenotvisibletoother
transactions.
TRANSACTION_
REPEATABLE_READ4
Uncommittedchangesarenotvisibletoothertransactions;nonrepeatablereadsarealsodisallowed.
TRANSACTION_
SERIALIZABLE8
Uncommittedchangesarenotvisibletoothertransactions;nonrepeatablereadsandphantomreadsarealsodisallowed.
Checkyourdatabasevendor'sspecificationsorliteratureforhowthedatabasesystemyouusehandlestransactionisolation.UsetheConnectionobject'sgetTransactionIsolation()methodtofindoutthevalueassociatedwithaparticulardatabasedriverthatJDBC-relatedcodeisusing.Thismethodreturnsanint.Forexample,a"2"returnvaluemeansthattheConnectionisassociatedwithaTRANSACTION_READ_COMMITTEDtransactionisolationlevel.
Example21-14runstwoSQLstatementswithinatransaction:itexecutesastoredprocedureandinitiatesanUPDATEstatement.Thenthecodecallscommit()ontheConnectionobjecttocommitanydatabasechangestotheunderlyingdatastore.IfthisSQLcodethrowsanexception,thetransactionisrolledbackwithacalltoConnection'srollback()method.ThismethodcallpreventsthepriorSQLstatementsfromhavinganyeffectontheunderlyingdatabase.
Figure21-7showstheoutputoftheservletinExample21-14,asitwouldappearinawebbrowser.
Figure21-7.Aservletwithadatabasetransactionprovidesbrowseroutput
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Recipe21.1onaccessingadatabasefromaservletwithoutaconnectionpool;Recipe21.2andRecipe21.3onusingaDataSourceonTomcat;Recipe21.4-Recipe21.6onusingDataSourceswithservletsandJSPsonWebLogic;Recipe21.7andRecipe21.8oncallingstoredproceduresfromservletsandJSPs;Recipe21.11onusingtransactionsinJSPs;Recipe21.12onfindingoutinformationaboutaResultSet.
Recipe21.11UsingTransactionswithJSPs
Problem
YouwanttorunSQLstatementswithin.atransactioninaJSP.
Solution
Usethesql:transactionJSTLtag.
Discussion
TheJSTLhasasql:transactiontagthatexecutesanynestedSQLactions(suchassql:update)inatransaction.
Thesql:transactiontagusesthesamejava.sql.Connectionmethodsthatyouwoulduseinatransaction-relatedservlet(Recipe21.10):setAutoCommit(false),commit(),androllback().
Example21-15usesaDataSourcethatisconfiguredinweb.xml,sothatnoneofthedatabase-relatedinformationappearsintheJSP.SeeRecipe23.6forhowtoconfigureaDataSourceinthedeploymentdescriptor.TheINSERTandSELECTSQLstatementsthatarenestedinsidethesql:transactiontagwillbothberolledbackifanyproblemsarisewithinthetransaction.
Example21-15.AJSPexecutesINSERTandSELECTSQLstatementsinatransaction
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%@tagliburi="http://java.sun.com/jstl/sql"prefix="sql"%>
<html>
<HEAD>
<TITLE>UsingaTransactionwithaJSP</TITLE>
</HEAD>
<bodybgcolor="white">
<h2>ViewAthleteData</h2>
<sql:transaction>
<sql:update>
insertintoathletevalues(2,'RachelPerry','rlpbwp1996',
'24-Feb-1996','F')
</sql:update>
<sql:queryvar="resultObj">
select*fromathlete
</sql:query>
</sql:transaction>
<table>
<c:forEachitems="${resultObj.rows}"var="row">
<c:forEachitems="${row}"var="column">
<tr>
<tdalign="right">
<b><c:outvalue="${column.key}"/></b>
</td>
<td>
<c:outvalue="${column.value}"/>
</td></tr>
</c:forEach>
</c:forEach>
</table>
</body>
</html>
AfterexecutingSQLwithinatransaction,theJSPdisplaysthedatabasetable'supdatedvalues.Thecontentofthesql:updateandsql:querytagsaretraditionalSQLstatements.
MakesuretoincludethepropertaglibdirectivetouetheJSTL1.0sqltaglibrary:
<%@tagliburi=
"http://java.sun.com/jstl/sql"prefix="sql"%>
Thesql:transactiontagalsohasanisolationattributeinwhichyoucanspecifyanisolationlevelforthetransaction(seeRecipe21.10).Hereisanexample:
<sql:transactionisolation="TRANSACTION_READ_COMMITTED">
<%--SQLstatementsandtagshere...--%>
</sql:transaction>
Figure21-8showstheoutputofthesqlTrans.jspfile.
Figure21-8.AJSPdisplaysanupdateddatabasetable
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;Chapter23ontheJSTLanditssqltaglibrary;Recipe21.1onaccessingadatabasefromaservletwithoutaconnectionpool;Recipe21.2andRecipe21.3onusingaDataSourceonTomcat;Recipe21.4-Recipe21.6onusingDataSourceswithservletsandJSPsonWebLogic;Recipe21.7andRecipe21.8oncallingstoredproceduresfromservletsandJSPs;Recipe21.10onusingtransactionsinservlets;Recipe21.12onfindingoutinformationaboutaResultSet.
Recipe21.12FindingInformationaboutaResultSet
Problem
Youwanttodynamicallydiscoverdetailsabouttherowsandcolumnsinajava.sql.ResultSet.
Solution
UsetheResultSetMetaDataclassobtainedbycallingthejava.sql.ResultSet'sgetMetaData()method.
Discussion
Webdeveloperssometimesneedtoworkwithdatabasetablesthathaveunknowncolumnnamesandtypes.Thejava.sqlpackagecontainsaveryusefulResultSetMetaDatainterfacethatdefinesmethodsdesignedtoprovideinformationaboutajava.sql.ResultSet.AResultSetencapsulatestherowsreturnedbyaSELECTSQLstatement.
Example21-16showsaservletthatqueriesanOracle8idatabaseforaResultSet,thendisplaysthecolumnnames,thecolumnindex,theSQLtypeofthecolumn,andthenumberofcharactersthecolumnrequirestodisplayitsvalues.
Example21-16.AservletusestheResultSetMetaDataclass
packagecom.jspservletcookbook;
importjava.sql.*;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.sql.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassDbMetaServletextendsHttpServlet{
DataSourcepool;
/*InitializetheDataSourceintheservlet'sinit()method
whichtheservletcontainercallsoncewhenitcreatesaninstanceof
theservlet*/
publicvoidinit()throwsServletException{
Contextenv=null;
try{
env=(Context)newInitialContext().lookup("java:comp/env");
pool=(DataSource)env.lookup("jdbc/oracle-8i-athletes");
if(pool==null)
thrownewServletException(
"'oracle-8i-athletes'isanunknownDataSource");
}catch(NamingExceptionne){
thrownewServletException(ne);
}
}//init
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
Stringsql="select*fromathlete";
Connectionconn=null;
Statementstmt=null;
ResultSetrs=null;
ResultSetMetaDatarsm=null;
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>DiscoveraResultSet</title></head><body>");
out.println("<h2>HereisInfoaboutthereturnedResultSet</h2>");
out.println("<tableborder='1'><tr>");
try{
//Getaconnectionfromthepool
conn=pool.getConnection();
//CreateaStatementwithwhichtorunsomeSQL
stmt=conn.createStatement();
//ExecutetheSQL
rs=stmt.executeQuery(sql);
//GetaResultSetMetaDataobjectfromtheResultSet
rsm=rs.getMetaData();
intcolCount=rsm.getColumnCount();
//printcolumnnames
printMeta(rsm,"name",out,colCount);
//printcolumnindex
printMeta(rsm,"index",out,colCount);
//printcolumntype
printMeta(rsm,"columntype",out,colCount);
//printcolumndisplaysize
printMeta(rsm,"columndisplay",out,colCount);
}catch(Exceptione){
thrownewServletException(e.getMessage());
}finally{
try{
stmt.close();
conn.close();
}catch(SQLExceptionsqle){}
}
out.println("</table></body></html>");
}//doGet
privatevoidprintMeta(ResultSetMetaDatametaData,Stringtype,
java.io.PrintWriterout,intcolCount)throwsSQLException{
if(metaData==null||type==null||out==null)
thrownewIllegalArgumentException(
"IllegalargspassedtoprintMeta()");
out.println("<tr>");
if(type.equals("table")){
out.println("<td><strong>Tablename</strong></td>");
for(inti=1;i<=colCount;++i){
out.println("<td>"+metaData.getTableName(i)+"</td>");
}
}elseif(type.equals("name")){
out.println("<td><strong>Columnname</strong></td>");
for(inti=1;i<=colCount;++i){
out.println("<td>"+metaData.getColumnName(i)+"</td>");
}
}elseif(type.equals("index")){
out.println("<td><strong>Columnindex</strong></td>");
for(inti=1;i<=colCount;++i){
out.println("<td>"+i+"</td>");
}
}elseif(type.equals("columntype")){
out.println("<td><strong>Columntype</strong></td>");
for(inti=1;i<=colCount;++i){
out.println("<td>"+metaData.getColumnTypeName(i)+
"</td>");
}
}elseif(type.equals("columndisplay")){
out.println("<td><strong>Columndisplaysize</strong></td>");
for(inti=1;i<=colCount;++i){
out.println("<td>"+metaData.getColumnDisplaySize(i)+
"</td>");
}
}
out.println("</tr>");
}//printMeta
}
Example21-16usesResultSetMetaDatamethodstoobtaininformationabouteachofthecolumnsintheResultSet.ThecodecallsthesemethodsinsideitsprintMeta()method.Forexample,thecode:
metaData.getColumnName(1)
returnsthenameofthefirstcolumnthetableschemaspecifies,suchas"USER_ID."Figure21-9showstheservlet'sHTMLoutputinawebbrowser.
Figure21-9.AservletdisplaysmetainformationaboutaResultSet
Usethejava.sql.DatabaseMetaDatainterfacetogetalargeamountofinformationaboutthedatabasesystemassociatedwiththejava.sql.Connectionthecodeisusing.TheConnectionmethodgetMetaData()returnsanobjectthatimplementstheDatabaseMetaDatainterface.
SeeAlso
TheJDBCspecification:http://java.sun.com/products/jdbc/download.html;TheResultSetMetaDataclass:http://java.sun.com/j2se/1.4.1/docs/api/java/sql/ResultSetMetaData.html;Recipe21.1onaccessingadatabasefromaservletwithoutaconnectionpool;Recipe21.2andRecipe21.3onusingaDataSourceonTomcat;Recipe21.4-Recipe21.6onusingDataSourceswithservletsandJSPsonWebLogic;Recipe21.7andRecipe21.8oncallingstoredproceduresfromservletsandJSPs;Recipe21.10andRecipe21.11onusing
transactionsinservletsandJSPs.
Chapter22.UsingCustomTagLibrariesIntroduction
Recipe22.1.CreatingaClassicTagHandler
Recipe22.2.CreatingaJSP1.2TLDforaClassicTagHandler
Recipe22.3.CreatingaJSP2.0TLDforaClassicTagHandler
Recipe22.4.PackagingaTagLibraryinaWebApplication
Recipe22.5.PackagingtheTagLibraryinaJARFile
Recipe22.6.UsingtheCustomTaginaJSP
Recipe22.7.HandlingExceptionsinaCustomTagClass
Recipe22.8.CreatingaSimpleTagHandler
Recipe22.9.CreatingaTLDforaSimpleTagHandler
Recipe22.10.UsingaSimpleTagHandlerinaJSP
Recipe22.11.CreatingaJSPTagFile
Recipe22.12.PackagingtheJSPTagFileinaWebApplication
Recipe22.13.PackagingtheJSPTagFileinaJAR
Recipe22.14.UsingaCustomTagAssociatedwithaTagFile
Recipe22.15.AddingaListenerClasstoaTagLibrary
Introduction
AverypowerfulfeatureofJavaServerPagestechnologyistheabilitytocreateyourownXMLtagsforuseinJSPs.CustomtagshavebeenapartoftheJSPspecificationsinceVersion1.1.JSP2.0isdedicatedtomakingcustomtagdevelopmentlesscomplexthanpriorversions.JSP2.0'sintroductionofsimpletaghandlersandtagfiles,whichwecoverinRecipe22.8-Recipe22.14,areabigpartofthisstrategy.
Let'sfamiliarizeourselveswithafewtermsbeforewemoveontocustomtagrecipes.AtagisaninstanceofanXMLelementandamemberofaspecifiednamespace.Forexample,theprefixforalltagsassociatedwiththiscookbookiscbck.TheJSPreferstoanindividualtagassociatedwiththecbcknamespace(say,themyTagtag)asfollows:
<cbck:myTag>whateverthistagdoes...</cbck:myTag>
TagsareXMLelements;therefore,theirnamesandattributesarecasesensitive.Acollectionoftagsthatprovidesimilarfunctionalityorthatlogicallycollaboratewitheachotheriscalledataglibrary.Developerscaninstalloneormoretaglibrariesinawebapplication.
AJavaclasscalledthetaghandlerprovidesthetag'sfunctionalityinaJSP.AcustomactionisatagthatyouinventforuseinJSPsandthatispoweredbehindthescenesbyatag-handlerobjectthatthewebcontainerkeepsinmemory.
AclassictaghandlerusesthetagextensionAPIthatevolvedfromJSPv1.1to1.2.AsimpletaghandlerisaJavaclassthatimplementstheSimpleTaginterface,whichJSP2.0introduced.
AtagfiledefinesacustomtaginJSPsyntax.Itisdesignedtomakelifeeasierfortagdevelopers.ThewebcontainergeneratesfromthetagfileaJavaclassthatimplementstheSimpleTaginterface,andthencreatesanobjectfromthatclasstointerpretthetag'suseinJSPs.
Finally,ataglibrarydescriptor(TLD)isanXMLfilethatprovidesamappingbetweenreferencestotaglibrariesinJSPs(withthetaglibdirective)andthetag-libraryclassesthatyouinstallinthewebapplication.ATLDisaconfigurationfile,similartoawebapplication'sdeploymentdescriptor.Therecipesinthischapterprovideexamplesofhowtocreateclassictaghandlers,simpletaghandlers,andtagfiles.Therecipesalsoshowhowtopackagethesecomponentsinwebapplications.
Recipe22.1CreatingaClassicTagHandler
Problem
YouwanttocreateaclassicJSP1.2-styletaghandlerforacustomaction.
Solution
CreateaJavaclassthatextendsoneoftheTagsupportclassesinthejavax.servlet.jsp.tagextpackage,suchasBodyTagSupport.
Discussion
TherearenumeroustypesofcustomtagsyoucancreateforJSPs,suchasactionsthatignoretheirbodies(emptytags),actionsthatarenestedwithinothercustomactions,andcustomtagsthatusetheirbodycontent.Infact,entirebookshavebeendedicatedsolelytoJSPcustomtagdevelopment!Insteadofbeingexhaustiveinthisbook,IshowhowtocreateafairlysimpleclassictagthataddsanimagelogotoaJSPpagewithatextmessage.Youcantheninferdetailsforyourownprogrammingtasksfromthisexample.
Thesampletagisdesignedtoallowapagedesignertospecifyanlogo'simage,itswidthandheight,andatextmessagetositalongsidetheimage.
Example22-1showstheclassictaghandlerforthiscustomaction.ThisJavaclassextendsBodyTagSupport,sinceitusesthetag'snestedcontentforthelogo'stextmessage.
Example22-1.Aclassictaghandlerforinsertinganimageandmarkup
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjavax.servlet.jsp.*;
importjavax.servlet.jsp.tagext.*;
/**ThistaggeneratesathumbnailimageusingtheHTMLimgtag,nexttoatextmessage.
TheuserspecifiesthecontentofthemessageandtheHeadinglevel(i.e.,<H1>-<H6>)*/
publicclassLogoTagextendsBodyTagSupport{
//Thesevariablerepresentthecustomtag'sattributes
privateStringheading=null;
privateStringimage=null;
privateStringwidth=null;
privateStringheight=null;
//thismethodassumesthatattributepropertieshavebeenset.
publicintdoStartTag()throwsJspException{
try{
inth=newInteger(heading).intValue();
if(!(h>0&&h<7))
thrownewJspException(
"The'heading'attributevaluemustbetween1and6inclusive.");
}catch(Exceptione){thrownewJspException(e.getMessage());}
returnEVAL_BODY_BUFFERED;
}
publicintdoEndTag()throwsJspException{
JspWriterout=pageContext.getOut();
//the'images'directoryislocatedinthewebapp's
//rootdirectory
StringimgDir=((HttpServletRequest)pageContext.
getRequest()).getContextPath()+"/images/";
//getthetextprovidedbetweenthecustomaction's
//startandendtags
Stringmessage=getBodyContent().getString().trim();
try{
//buildtheHTMLimgtag
out.println("<imgsrc=\""+imgDir+image+"\"width=\""+width+
"\"height=\""+height+"\"align=\"left\">"+"<H"+heading+">"+
message+"</H"+heading+">");
}catch(java.io.IOExceptionio){}
returnEVAL_PAGE;
}//doEndTag
//methodsdesignedtosetattributevalues
publicvoidsetHeading(Stringlevel){
this.heading=level;
}
publicvoidsetImage(Stringname){
this.image=name;
}
publicvoidsetWidth(Stringwidth){
this.width=width;
}
publicvoidsetHeight(Stringheight){
this.height=height;
}
//theJSPcontainermaycacheandreusetaghandlerobjects.
//thismethodreleasesinstancevariablessothatthetaghandler
//canbereusedafresh
publicvoidrelease(){
heading=null;
image=null;
width=null;
height=null;
}//release
}
ClassictaghandlersarelikeJavaBeans.Youdeclarethecustomtag'sattributesasinstancevariables,orproperties,anddefinesettermethodsforeachattribute.Ifyoujustwanttomanipulatethecustomtag'sbody,definethedoEndTag()method.WhentheJSPcontainerinvokesdoEndTag(),developerscanusethismethodtoevaluatethebodycontentthatthetaguserhasplacedbetweentheaction'sstartandendtags.Example22-1alsodefinesthedoStartTag()methodtocheck
thatthetaguserhasincludedavalidvaluefortheheaderattribute(anumberbetweenoneandsix,inclusive,forthisexamplecode).
WhenthedoStartTag()methodisinvoked,anyattributevaluesthattheuserhassetareavailable,butthetag'sbodycontentisnot.
ThedoEndTag()methodusesthevarioustagattributevaluestobuildanimgandHtagthatresultsinthedisplayofasimplelogointheJSPpagewherethetagisused.Here'sanexampleofhowaJSPwouldusetheactiondefinedbythistaghandler:
<%--importthetaglibrarywith'taglib'directive--%>
<%@tagliburi="jspservletcookbook.com.tags"prefix="cbck"%>
<%--JSPpagecontinues...--%>
<%--Usethe'logo'tag--%>
<cbck:logoheading="1"image="stamp.gif"width="42"height="54">Thanksforvisiting</
cbck:logo>
Figure22-1showsaJSPthatusesthetagdefinedbyExample22-1.
Figure22-1.AJSPpageusesacustomtagthatdisplaysanimageandaheading
TheJSPusingthistagoutputsHTMLthatlookslikethis:
<imgsrc="/home/images/stamp.gif"width="42"height="54"align="left">
<H1>Thanksforvisiting</H1>
Youmightrespondbyexclaiming,"ThedesignercanjustentertheseHTMLtagsmanually,andtheydon'thavetodealwiththecustomtag'ssyntax!"Thisisabsolutelytrue;however,thetagtakescareofthedefaultlocationfortheimagesdirectory,positionsandalignstheimage,andcheckswhethertheattributeleveliscorrect.Inotherwords,itperformsalotofroutineworkandremovesthepossibilityofsillytypographicalmistakes.
Alsoconsiderthatthisisasimpleexample;whatiftheimagewasaFlashfileinstead?AcustomtagcouldtakecareofallofthecomplexdetailsforembeddingtheFlashintheHTMLpageandgeneratingproprietaryattributevalues,leavingthegraphicalpositioningofthemediafileuptothetaguser.
Aniceruleofthumbwithcustomtagsisthis:leaveautomated,complex,ortediousworktothetaghandler,andreserveconfigurabledetailsforthetag'sattributes.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;
Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4andRecipe22.5onpackagingtaglibrariesinawebapplication;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.11-Recipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustom-tagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.2CreatingaJSP1.2TLDforaClassicTagHandler
Problem
YouwanttocreateaJSP1.2TLDfileforoneormorecustomtags.
Solution
CreatetheXMLfileusingtheproperDOCTYPEdeclarationforaJSP1.2TLD.
Discussion
ATLDisanXMLfilethatdescribesyourcustomtags,thetag'sattributes(ifany),aswellastheJavaclassesthatprovidethetag'sfunctionality.TheJSPcontainerusesthisconfigurationfilewhenitinterpretscustomtagsthatappearinJSPpages.IfyouareusingaJSPv1.2container,yourtaglibrary'sTLDhastheDOCTYPEdeclarationshowninExample22-2.ThisTLDdescribesthetaghandlerofthepreviousrecipe.
Example22-2.TheTLDfileforaclassicJSP1.2taghandler
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEtaglib
PUBLIC"-//SunMicrosystems,Inc.//DTDJSPTagLibrary1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>cbck</short-name>
<!--HereistheURIyouusewiththe'taglib'directiveintheJSP-->
<uri>com.jspservletcookbook.tags</uri>
<description>Cookbookcustomtags</description>
<tag>
<name>logo</name>
<!--makesuretousethefullyqualifedclassname-->
<tag-class>com.jspservletcookbook.LogoTag</tag-class>
<body-content>JSP</body-content>
<description>ThistagwritesalogoinsidetheJSP.</description>
<attribute>
<name>heading</name>
<!--Thelogotagrequiresthisattribute-->
<required>true</required>
<!--TheattributecantakeaJSPexpressionasavalue-->
<rtexprvalue>true</rtexprvalue>
<description>Theheadinglevelforthelogo;1through6.
</description>
</attribute>
<attribute>
<name>image</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>Theimagenameforthelogo.</description>
</attribute>
<attribute>
<name>width</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>Theimagewidthforthelogo.</description>
</attribute>
<attribute>
<name>height</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>Theimageheightforthelogo.</description>
</attribute>
</tag>
</taglib>
InJSP1.2and2.0,aJSPcontainerautomaticallysearchesWEB-INF,aswellastheMETA-INFdirectoryofyourapplication'sJARfiles,foranyfilethatendswiththeextension.tld.
Because.tldisafixedextension,itismandatorytogiveyourtaglibrarydescriptorfilenamesthatendin.tld.
ThecontainerthenusestheinformationitfindsintheTLDtointerpretcustomtagsthatthewebapplicationmayuse.Forexample,thecontainermapstheurielementsitfindsintheTLDtotheURIsspecifiedbyanytaglibdirectivesinJSPfiles.Example22-2specifiesauriofcom.jspservletcookbook.tagsforthetaglibrarythatcontainsthelogotag.AtaglibdirectivethatusesthistaglibraryinaJSPlookslikethis:
<%@tagliburi="com.jspservletcookbook.tags"prefix="cbck"%>
WhenthelogotagappearslateronintheJSP,theJSPcontainerknowsthatthetagbelongsinthetaglibrarywiththecom.jspservletcookbook.tagsurivalue,andthecontainercanevaluatetheJSP'stagusebasedontheTLD'sspecificationofthetagclassandthetag'svariousattributes.BasedontheTLD,theJSPcontainerknowsthatthelogotag'sattributesareallrequired,soaJSPthatusesthelogotagandomitsanattributefailstocompile.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.3oncreatingaJSP2.0TLDfilefortaglibraries;Recipe22.4andRecipe22.5onpackagingtaglibrariesinawebapplication;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.11-Recipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.3CreatingaJSP2.0TLDforaClassicTagHandler
Problem
YouwanttocreateaJSP2.0TLDfileforataglibrary.
Solution
Createataglibrarydescriptorwiththepropertaglibrootelement,includingthetaglib'svariousxmlnsattributesandvalues.
Discussion
IfyouareusinganyJSP2.0featureswithyourtaglibraryandTLD,suchasafunctionortag-fileelement,thenyoumustusetheJSP2.0-styleTLD,asshowninExample22-3.
TheJSP2.0TLDisbackwardcompatiblewithelementsdefinedintheJSP1.2DTD.ThereforeyoucanusethetaglibandtagelementsastheyarespecifiedinanyexistingJSP1.2TLDswhenyouupgradeyourTLDfiletoJSP2.0.Forexample,theonlydifferencebetweentheTLDinExample22-3andtheJSP1.2TLDinExample22-2isthetaglibstarttag,whichmusthaveexactlythesamecontentasshownhere.
Example22-3.TheJSP2.0TLDfileforourclassictaghandler
<taglibxmlns="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-jsptaglibrary_2_0.xsd"
version="2.0"
>
<!--THERESTOFTHEXMLCONTENTISALMOSTEXACTLYTHESAMEASTHEJSP1.2TLDVERSION
EXCEPTFOR<jsp-version>2.0</jsp-version>AND<body-content>scriptless</body-content>.The
"scriptless"valuemeansthatthecontentofthetagcanonlybetemplatetext(suchas
HTMLcontent),ExpressionLanguagecode,orJSPactionelements,butnot"scripting"
elementssuchastheJSPcodedelineatedby<%%>-->
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>cbck</short-name>
<uri>com.jspservletcookbook.tags</uri>
<description>Cookbookcustomtags</description>
<tag>
<name>logo</name>
<tag-class>com.jspservletcookbook.LogoTag</tag-class>
<body-content>scriptless</body-content>
<description>ThistagwritesalogoinsidetheJSP.</description>
<attribute>
<name>heading</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>
Theheadinglevelforthelogo;1through6.
</description>
</attribute>
<attribute>
<name>image</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>Theimagenameforthelogo.</description>
</attribute>
<attribute>
<name>width</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>Theimagewidthforthelogo.</description>
</attribute>
<attribute>
<name>height</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>Theimageheightforthelogo.</description>
</attribute>
</tag>
</taglib>
TheJSP2.0TLDisbasedonanXMLSchemafile,ratherthanaDTD(theXMLSchemafile:http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd).
XMLSchemasallowthedefinersofXMLdocumentstocreatemorecomplexelementsandattributesthanthoseallowedinDTDs.XMLSchemasarealsodesignedtobevalidXMLdocumentsthemselves,whichmakesiteasiertointegratethemwithXML-basedapplications.
ThetaglibelementinExample22-3hasfourattributes.ThexmlnsattributespecifiesthattheTLDhasthesamedefaultnamespaceasallJ2EEdeploymentdescriptors:http://java.sun.com/xml/ns/j2ee.
AnamespaceisauniqueidentifierthathelpsavoidthecollisionoftwoXMLelementsofthesamename.Forexample,thetaglibelementthatispartofthehttp://java.sun.com/xml/ns/j2eenamespaceisdifferentfromataglibelementthatmightbedefinedaspartofthehttp://acme.comnamespace.Anamespacehastobeuniqueonlywithinitsdomain(suchasanInternetURL);itdoesnotnecessarilyrepresentanactualwebdocument.
Thexmlns:xsiattributespecifiesthenamespaceforasetofXMLelementsrelatedtoXMLSchemainstances.Thexsi:schemaLocationattributespecifiesthelocationoftheXMLSchemaonwhichthecurrentXMLdocumentisbased.
AnXMLSchemadescribesarelatedsetofelementsandattributes.AnXMLSchemainstanceisanXMLdocumentthatusesthepreviouslydefinedXMLelementsandattributes.ThisconceptissimilartoaJavaclassanditsobjectinstances.
Finally,thetaglibelement'sversionattributespecifiestheJSP-specificationversiononwhichthetaglibraryisbased,asinJSP2.0.
SeeAlso
TheXMLschemafilefortheJSP2.0TLD:http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd;Recipe22.2oncreatingaJSP1.2TLDfilefortaglibraries;Recipe22.4andRecipe22.5onpackagingtaglibrariesinawebapplication;Recipe22.6on
usingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.11-Recipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.4PackagingaTagLibraryinaWebApplication
Problem
Youwanttomakeyourtaglibraryavailableinawebapplication.
Solution
PlaceyourTLDfileinWEB-INForaWEB-INFsubdirectory(withtheexceptionofWEB-INF/libandWEB-INF/classes).PlacethetaghandlerclassorclassesinWEB-INF/classes.
Discussion
PackagingyourtaglibraryoutsideofaJARfileistypicallyatwo-stepprocess:
1. StoretheTLDfileintheWEB-INFdirectoryoraWEB-INFsubdirectory,andaJSPcontainer(compliantwithVersions1.2and2.0)automaticallyconfiguresyourtaglibrary.TheTLDfilemusthavea.tldextension.Forexample,ifyoustoreamytags.tldinWEB-INF/tlds,thentheJSPcontainerautomaticallyfindsyourTLDfileandconfigureyourtaglibrary.
TheJSP2.0specificationstatesthatTLDsshouldnotbeplacedinWEB-INF/liborWEB-INF/classes.TheJSPcontainerwillnotlookfortheTLDsintheselocations.
2. Makesurethetaghandlerclassesforyourtaglibraryhaveapackagename(suchascom.jspservletcookbook)andarestoredinWEB-INF/classesorinaJARfileinWEB-INF/lib.
Thenextrecipeshowshowtopackageyourtaglibrary,includingtheTLD,inaJARfile.
SeeAlso
TheXMLschemafilefortheJSP2.0TLD:http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd;Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.5onpackagingtaglibrariesinaJARfile;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.11-Recipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustom-tagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.5PackagingtheTagLibraryinaJARFile
Problem
YouwanttomakeyourtaglibraryavailableinaJARfile.
Solution
CreateaJARfilethatcontainsyourtaghandlerclassorclassesinthecorrectdirectorystructure(withsubdirectorynamesmatchingthepackagenames).PlacethetaglibrarydescriptorfileintheJAR'sMETA-INFdirectory.ThenputtheJARintheWEB-INF/libdirectoryofyourwebapplication.
Discussion
Tomakeyourtaglibraryportable,storeallofyourtaghandlerclassesandtagfilesinaJARfile.
InaJAR,storeanytagfilesinMETA-INF/tagsorasubdirectoryofMETA-INF/tags.Ifyoudon't,theJSPcontainerwillnotrecognizethemaslegitimatetagfiles.SeeRecipe22.11fordetails.
YoucangeneratethisJARfilefromadirectorythatcontainsyourtaglibraryclasses,includingtheirpackage-relatedsubdirectories.Forexample,thelogotagIdevelopedinthischapterhasapackagename
ofcom.jspservletcookbook,sotherelativepathtothisfileiscom/jspservletcookbook/LogoTag.class.IncludeaMETA-INFdirectoryatthetoplevelofthedirectorywheretheclassesarestored(e.g.,inthesamedirectoryastheonecontainingcom).PlaceyourtaglibrarydescriptorfileintheMETA-INFdirectoryoraMETA-INFsubdirectory.
Ifyourlibraryincludesanytagfiles,placetheminMETA-INF/tagsorasubdirectoryofMETA-INF/tags.Changetothedirectorycontainingallthesesubdirectoriesandtypethefollowingcommandline,substitutingyourownJARfilenameforcookbooktags.jar:
jarcvfcookbooktags.jar.
Don'tforgetthatperiod(.)characterattheend.Thistellsthejartooltoincludeallofthefilesanddirectoriesthatthecurrentdirectorycontainsinthearchive.
Makesureyourcomputer'sPATHenvironmentvariableincludesthepathtothebindirectoryofyourJavaSDKinstallation,asinh:\j2sdk1.4.1_01\bin.ThisallowsyoutotypejaratthecommandlinetolaunchtheJavajartool.
Toinstallthetaglibrary,justtaketheresultingJARfileandmoveitintoyourwebapplication'sWEB-INF/libdirectory.
TheJSPcontainer(inJSP1.2and2.0)automaticallylooksintheJAR'sMETA-INFdirectoryfortheTLDfileyoudonothavetoincludeataglibelementintheweb.xmldeploymentdescriptor.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4onpackagingataglibraryinawebapplicationwithoutusing
aJARfile;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.11andRecipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.6UsingtheCustomTaginaJSP
Problem
Youwanttouseacustomtagthatyouhavedevelopedandinstalled.
Solution
IncludeataglibdirectiveatthetopoftheJSP.Thetaglibdirectivemustidentifytheuriforyourtaglibrary,asthaturiisspecifiedinyourTLDfile.
Discussion
Tousethecustomtagsfromyourtaglibrary,theJSPhastohaveataglibdirective,asinExample22-4.TheuriattributematchestheuriyourTLDfilespecifies(seeRecipe22.5).Theprefixattributespecifiesthenamespaceforyourtags.Example22-4specifiestheprefixcbck;therefore,theJSPusesthelogotagfromthattaglibraryinthemannerof<cbck:logo>...</cbck:logo>.
Ifthetagenclosesbodycontent(it'snotanemptytag),makesuretoclosethetagproperly,asin</cbck:logo>asopposedto</logo>.
IftheJSPdoesnotusethetagasspecifiedintheTLD(forexample,ifitleavesoutamandatoryattribute),theJSPwillfailtocompilethefirsttimeitisrequested.
Example22-4.TheLogotagusedinaJSP
<%@tagliburi="jspservletcookbook.com.tags"prefix="cbck"%>
<html>
<head><title>Micasaessucasa</title></head>
<body>
<cbck:logoheading="<%=request.getParameter("level")%>"image="stamp.gif"width="42"
height="54">Thanksforvisiting</cbck:logo>
Here'salltheotherstuffthispagecontains...
</body>
</html>
InExample22-4,thelogotag'sheadingattributetakesaruntimeexpressionvaluesothattheusercandynamicallysettheattributevalue,asinthefollowingURL:http://localhost:8080/home/logoTest.jsp?level=1.
Figure22-2showsthewebbrowserdisplayforthisJSP.
Figure22-2.Thewebbrowserdisplayofacustomtagoutput
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4andRecipe22.5onpackagingataglibraryinawebapplication;Recipe22.7onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.11-Recipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.7HandlingExceptionsinaCustomTagClass
Problem
Youwantyourcustomtaghandlertodealwithanyexceptionsthrowninsidethetag.
Solution
ImplementtheTryCatchFinallyinterfaceinyourtaghandler.
Discussion
ThetagextensionAPIprovidestheTryCatchFinallyinterface,whichyoucanimplementinyourtaghandlerclasstowritecodedealingwithanyexceptionsthetaghandlermightthrow.IftheclassimplementsTryCatchFinally,itmustincludethemethodsdoCatch()anddoFinally().IndoCatch(),thecodehasaccesstoanyThrowableobjectthrownbydoStartTag()ordoEndTag(),forinstance.IndoFinally(),thecodeclosesanyresourcesthetaguses,suchasadatabaseconnection.
Ingeneral,thisinterfaceallowsthetaghandleritselftocatchandhandleanyexceptionsthatdonotaffecttheoutputoftheJSPenclosingthetag.Example22-5usesthesamecodeasExample22-1,butadditionalmethodsareaddedbyimplementingtheTryCatchFinallyinterface.
Example22-5.Alogotaghandlerthatcatchesany
exceptions
packagecom.jspservletcookbook;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjavax.servlet.jsp.*;
importjavax.servlet.jsp.tagext.*;
/**ThistaggeneratesathumbnailimageusingtheHTMLimgtag,nexttoatextmessage.
TheuserspecifiesthecontentofthemessageandtheHeadinglevel(i.e.,<H1>-<H6>)*/
publicclassLogoTagextendsBodyTagSupportimplementsTryCatchFinally{
privateStringheading=null;
privateStringimage=null;
privateStringwidth=null;
privateStringheight=null;
//thismethodassumesthatattributepropertieshavebeenset.
publicintdoStartTag()throwsJspException{
try{
inth=newInteger(heading).intValue();
if(!(h>0&&h<7))
thrownewJspException(
"The'heading'attributevaluemustbetween1and6"+
"inclusive.");
}catch(Exceptione){
thrownewJspException(e.getMessage());
}
returnEVAL_BODY_BUFFERED;
}
publicintdoEndTag()throwsJspException{
JspWriterout=pageContext.getOut();
StringimgDir=((HttpServletRequest)pageContext.getRequest()).
getContextPath()+"/images/";
Stringmessage=getBodyContent().getString().trim();
try{
out.println("<imgsrc=\""+imgDir+image+"\"width=\""+
width+"\"height=\""+height+"\"align=\"left\">"+"<H"+
heading+">"+message+"</H"+heading+">");
}catch(java.io.IOExceptionio){}
returnEVAL_PAGE;
}//doEndTag
/*Thenexttwomethodshavetobeimplementedinthisclasssincetheclassimplements
TryCatchFinally*/
publicvoiddoCatch(Throwablet){
try{
//printtheexceptionmessageinsidetheJSPwherethetag
//appears
pageContext.getOut().println(t.getMessage()+"<br/>");
}catch(java.io.IOExceptionio){}
}
publicvoiddoFinally(){
//donothinghere,sincewedon'thaveanyresourcesopen
//likedatabaseconnections
}
publicvoidsetHeading(Stringlevel){
this.heading=level;
}
/*THERESTOFTHESOURCECODEFROMEXAMPLE22-1CONTINUES...*/
}
Ifthetagthrowsanexception,thenthewebcontainerinvokesthedoCatch()methodandthetaghandlerprintstheexceptionmessagewheretheJSPwouldotherwiseoutputtheimageproducedbythetag.OurdoFinally()methoddoesnotdoanything,becausethiscodedoesnothaveanyopenresourcessuchasaFileInputStream.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4andRecipe22.5onpackagingataglibraryinawebapplication;Recipe22.6onusingthecustomtaginaJSP;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.11-Recipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition
(O'Reilly).
Recipe22.8CreatingaSimpleTagHandler
Problem
YouwanttocreateaJSP2.0simpletaghandler.
Solution
CreateaJavaclassthateitherimplementstheSimpleTaginterfaceorextendstheSimpleTagSupportclass.
Discussion
Inanefforttosimplifycustomtagdevelopment,theJSP2.0specificationaddedthejavax.servlet.jsp.tagext.SimpleTaginterfaceandtheSimpleTagSupportclass.TheSimpleTagSupportclassisdesignedtobethebaseclassfortaghandlersthatimplementSimpleTag.Thesetaghandlershavetoimplementjustonemethod,doTag().
TheJSP2.0specificationstatesthatvendorsshouldnotcachesimpletaghandlers,sodevelopersdonothavetoworryaboutthereuseoftaghandlerobjectsandreleasingobjectstateintheircode.
Example22-6mimicsthelogotaghandlercreatedinearlierrecipes,butusestheSimpleTagSupportclassfromtheJSP2.0APIinstead.
Example22-6.Asimpletaghandlerdisplayingalogo
packagecom.jspservletcookbook;
importjava.io.IOException;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjavax.servlet.jsp.*;
importjavax.servlet.jsp.tagext.*;
/**ThistaggeneratesathumbnailimageusinganHTMLimgtag,alignednexttoatext
message.TheuserspecifiesthecontentofthemessageandtheHeadinglevel(i.e.,<H1>-
<H6>)*/
publicclassSimpleLogoTagextendsSimpleTagSupport{
privateStringheading=null;
privateStringimage=null;
privateStringwidth=null;
privateStringheight=null;
publicvoiddoTag()throwsJspException,IOException{
//JspContextprovidesaccesstotheJspWriterforgenerating
//textfromthetag.Youcanalsogetanystoredattributevalues
//usingJspContext
JspContextjspContext=getJspContext();
//thismethodassumesthatattributepropertieshavebeenset.
try{
inth=newInteger(heading).intValue();
if(!(h>0&&h<7))
thrownewJspException(
"The'heading'attributevaluemustbetween1and6"+
"inclusive.");
}catch(Exceptione){thrownewJspException(e.getMessage());}
//GetaJspWritertoproducethetag'soutput
JspWriterout=jspContext.getOut();
//thevalueofthe'imgDir'attributeisthewebapp's/images
//directory;thedirectorypathisstoredinasessionattribute
StringimgDir=(String)jspContext.findAttribute("imgDir");
if(imgDir==null||"".equals(imgDir))
thrownewJspException(
"Noattributeprovidedspecifyingtheapplication's"+
"imagedirectory.");
//displaytheimgandHHTMLtags
out.println(newStringBuffer("<imgsrc=\"").append(imgDir).
append(image).append("\"width=\"").append(width).
append("\"height=\"").append(height).append("\"align=\"left\">").
append("<H").append(heading).append(">").toString());
//getJspBody()returnsa'JspFragment'object;calling'invoke()'
//onthisobjectwitha'null'parameterwillusetheJSPpage's
//JspWritertooutputthetag'snestedcontentintheJSP
getJspBody().invoke(null);
out.println(newStringBuffer("</H").append(heading).
append(">").toString());
}//doTag
//Attribute-relatedsettermethods
publicvoidsetHeading(Stringlevel){
this.heading=level;
}
publicvoidsetImage(Stringname){
this.image=name;
}
publicvoidsetWidth(Stringwidth){
this.width=width;
}
publicvoidsetHeight(Stringheight){
this.height=height;
}
}//SimpleLogoTag
ThissimpletaghandleraccessesaJspContextobjectbycallingtheSimpleTagSupport'sgetJspContext()method.ThecodeusestheJspContexttoobtainthevalueofanattributestoredinthesession,aswellastoaccessaJspWritertogeneratethetag'soutput:
JspContextjspContext=getJspContext();
//furtheralonginthecode...
JspWriterout=jspContext.getOut();
//thevalueofthe'imgDir'attributeisthewebapp'simages
//directory;itisstoredinasessionattribute
StringimgDir=(String)jspContext.findAttribute("imgDir");
//codecontinues...
CallingtheSimpleTagSupport'sgetJspBody()methodreturnsaJspFragmentobject,whichrepresentsachunkofJSPcodeasanobject.Callingthisobject'sinvoke()methodwithnullastheparameterdirectstheoutputofthefragmenttotheJspWriteravailabletothetaghandler:
//Getthetag'sbodycontentandoutputitusingtheJspWriter
//thatisavailablebycallingJspContext.getOut()
getJspBody().invoke(null);
ThiscodedisplaysthecontentortextthattheJSPdeveloperincludedwithinthecustomaction'sstartandendtags.Thetaghandlerusesthetag'sbodycontentasthetextuallogomessage.Figure22-1inRecipe22.1showswhattheJSPpagelookslikeinawebbrowser.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4andRecipe22.5onpackagingataglibraryinawebapplication;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.9oncreatingaTLDforasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.11-Recipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.9CreatingaTLDforaSimpleTagHandler
Problem
YouwanttocreateaTLDforasimpletaghandler.
Solution
UsetheJSP2.0-styleTLDforthesimpletaghandler.
Discussion
ThesimpletaghandlerderivesfromtheJSP2.0API,soyoucanusetheTLDversionfromJSP2.0aswell.Example22-7showsthetaglibstarttagandthevariousxmlnsattributesthatyourTLDmustreproduceexactly.Then,unlessyouareusingJSP2.0TLDfeaturessuchasthetag-fileelement,youcanspecifythetagelementanditsnestedelementswiththesameXMLsyntaxthatyouusedforthepriorTLDversion.
Example22-7.AJSP2.0TLDfileforasimpletaghandler
<taglibxmlns="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-jsptaglibrary_2_0.xsd"
version="2.0"
>
<!--THERESTOFTHEXMLCONTENTISTHESAMEASTHEJSP1.2TLDVERSIONEXCEPTFOR<jsp-
version>2.0</jsp-version>-->
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>cbck</short-name>
<uri>com.jspservletcookbook.tags</uri>
<description>Cookbookcustomtags</description>
<tag>
<name>simplelogo</name>
<tag-class>com.jspservletcookbook.SimpleLogoTag</tag-class>
<body-content>JSP</body-content>
<description>ThistagwritesalogoinsidetheJSP.</description>
<attribute>
<name>heading</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>
Theheadinglevelforthelogo;1through6.
</description>
</attribute>
<attribute>
<name>image</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>Theimagenameforthelogo.</description>
</attribute>
<attribute>
<name>width</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>Theimagewidthforthelogo.</description>
</attribute>
<attribute>
<name>height</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>Theimageheightforthelogo.</description>
</attribute>
</tag>
</taglib>
Tousethesimpletaghandlerinawebapplication,placetheTLDinasubdirectoryofWEB-INFlikeWEB-INF/tlds.Or,storetheTLDinaJARfile'sMETA-INFdirectoryorasubdirectorythereof.ThenputtheJARintheWEB-INF/libdirectory.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.2-Recipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4-Recipe22.5onpackagingataglibraryinawebapplication;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.8oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.11-Recipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclassto
ataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.10UsingaSimpleTagHandlerinaJSP
Problem
Youwanttouseacustomtagbasedonasimpletaghandler.
Solution
UsethetaglibdirectiveintheJSP,specifyingtheproperuriattributeforthetaglibrary.
Discussion
Makesuretopackagethetaglibrary,thesimpletaghandler,anditsassociatedTLD,asdescribedbyRecipe22.4andRecipe22.5andthenoteinRecipe22.9.Example22-8showstherestofthesetupneededtousethetaginaJSP.
Simpletaghandlersaredesignedtobeeasiertodevelop(byhavingonlyonemethodthatyouneedtoimplement:voiddoTag()).UsetheassociatedtagsinaJSPthesamewayyouusethetagsassociatedwithclassictaghandlers.
Example22-8.AJSPusesatagdefinedbyasimpletaghandler
<%@tagliburi="jspservletcookbook.com.tags"prefix="cbck"%>
<html>
<head><title>MeCasaSuCasa</title></head>
<body>
<%session.setAttribute("imgDir",(request.getContextPath()+
"/images/"));%>
<cbck:simplelogoheading=
"<%=request.getParameter(\"level\")%>"image=
"stamp.gif"width="42"height="54">
Thanksforvisitinghere</cbck:simplelogo>
Here'salltheotherstuffthispagecontains...
</body>
</html>
TheJSPinExample22-8obtainsthevalueforthelogotag'sheadingattributewithaJSPexpression.TheJSPpageuserprovidesthevalueintheURLasin:
http://localhost:8080/home/logoTest.jsp?level=1
TheJSP'soutputlooksthesameastheoutputshowninFigure22-1ofRecipe22.1.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4andRecipe22.5onpackagingataglibraryinawebapplication;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.11-Recipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.11CreatingaJSPTagFile
Problem
Youwanttocreateacustomtagintheformofatagfile.
Solution
CreatethetagfileusingJSPsyntaxandwithanextensionof.tagor.tagx.PlacethetagfileinWEB-INF/tagsorinMETA-INF/tagsinsideaJARfile,orinasubdirectoryofeitherofthesedirectories.
Discussion
JSP2.0introducedtagfiles,whicharecustomtagsthatyouwriteusingJSPsyntax.TagfilesaredesignedtoallowdeveloperswithlittleornoJavaexperiencetocreatesimpletagsusingonlyJSPandXMLelements.Inaddition,tagfilesdonotrequireaTLD,althoughyoucandescribeatagfileinaTLD(seeRecipe22.12).Ifyoucreatethetagfile,thendropitintheWEB-INF/tagsdirectory,theJSPcontainercompilesthefileintoataghandlerclassthefirsttimeitsassociatedtagisusedinaJSP.
TheJSPcontainerconvertsthetagfileintoaclassthatextendsjavax.servlet.jsp.tagext.SimpleTagSupport.SeeRecipe22.8formoredetailsonthatclass.
Tagfileshaveintroducedafewmoredirectivesandstandardactions,suchasthetagandattributedirectives,aswellasthejsp:doBody
action.Example22-9showsthesenewsyntaxelements.Theexamplecreatesthesamelogotagwehaveworkedonthroughoutthischapter,butusestagfileformat.
Recipe22.14showshowtheresultingcustomtagcanbeusedinaJSP.
Example22-9usesatagdirectivetospecifythatthetag'sbodycontent(thetextthatappearsbetweenthestartandendtags)isscriptless.Thismeansthatthebodycontentcontainsonlytemplatetext,ELcode,andJSPactionelements.
Ifyouaredefininganemptytag,thebody-contentvalueis"empty."IfthetagacceptsJSPcodeinitsbody,use"JSP"forthisvalue.Thefourthbody-contentoptionis"tagdependent,"meaningthatthetagitselfinterpretsthecodeinitsbody(suchasSQLstatements).
SinceatagfilecanusenormalJSPsyntax,Example22-9usesataglibdirectivetousetheJSTL(seeChapter23).Thentheexampledefineseachoneofthetag'sattributes.
Rememberthattagandattributearedirectives,sotheircodestartswith"<%@."
Example22-9.AtagfilegeneratesacustomtagthatinsertsalogoinaJSP
<%@tagbody-content="scriptless"description="WritestheHTMLcodeforinsertingalogo."
%>
<%@taglibprefix="c"uri="http://java.sun.com/jstl/core"%>
<%@attributename="heading"required="true"rtexprvalue=
"true"description="Theheadinglevelforthelogo."%>
<%@attributename="image"required="true"rtexprvalue=
"true"description="Theimagenameforthelogo."%>
<%@attributename="width"required="true"rtexprvalue=
"true"description="Theimagewidthforthelogo."%>
<%@attributename="height"required="true"rtexprvalue=
"true"description="Theimageheightforthelogo."%>
<imgsrc="<c:outvalue="${imgDir}${image}"/>"width=
"<c:outvalue="${width}"/>"height="<c:outvalue=
"${height}"/>"align="left">
<H<c:outvalue="${heading}"/>><jsp:doBody/></H<c:outvalue="${heading}"/>>
TheattributesfortheattributedirectivearethesameastheattributesthatyouuseforaJSP1.2-styleTLDfile(seeRecipe22.2).Sinceatagfileacceptsplaintemplatetext,thisishowwehavesetuptheHTMLimgtagthatthetagfileisdesignedtogenerate.
Theimgtaggetsthevaluesforitsownattributesusingthec:outJSTLtagandtheEL(seeChapter23).Forexample,theexpression"${imgDir}"returnsthevalueforastoredobjectattributeofthesamename,whichspecifiesadirectorythatcontainstheimageusedinthelogo.Theexpression"${image}"returnsthevalueofthetag'simageattributewhich,bythislineofthecode,hasalreadybeensetbytheuser.
Thejsp:doBodystandardactionisaniftywaytooutputthetextbetweenthecustomaction'sstarttagandendtag.
Thejsp:doBodyaction,aswellasthetag,attribute,andvariable(notshowninthisrecipe)directives,canbeusedonlyintagfiles.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4andRecipe22.5onpackagingataglibraryinawebapplication;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.12-Recipe22.14onusingaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.12PackagingtheJSPTagFileinaWebApplication
Problem
Youwanttostorethetagfileforuseinawebapplication.
Solution
PlacethetagfileinWEB-INF/tagsorinMETA-INF/tagsinsideaJARfileorinasubdirectoryofeitherofthesedirectories.IfyoudothisyoudonotneedtodescribethetaginaTLDfile.
Discussion
TheJSPcontainerfindsthetagfilebyusingthetagDirattributeofthetaglibdirective.Inotherwords,thetagDirattributeprovidesthepathtothewebapplicationdirectorywhereyoustoredthetagfile.Here'sanexample:
<%@taglibprefix="cbck"tagdir="/WEB-INF/tags"%>
Aslongasyouplacethetagfile,whichhasa.tagextension(or.tagxextensionifthetagfileisinXMLsyntax)in/WEB-INF/tags,JSPscantousethetagassociatedwiththetagfile.
TheJSPhastopositionthetaglibdirectiveinthecodebeforetheJSPusestheassociatedcustomtag.
TheJSP2.0TLDcanalsospecifythetagfileinthefollowingmanner:
<tag-file>
<name>dbSelect</name>
<path>/WEB-INF/tags/dbtags</path>
</tag-file>
ThisTLDentryspecifiesatagfilenameddbSelect.tag,whichresidesinthe/WEB-INF/tags/dbtagsdirectory.Thepathattributemustbeginwith"/META-INF/tags"ifthetagfileresidesinaJAR,and"/WEB-INF/tags"ifthetagfileislocatedinaWebArchive(WAR)fileorinanonarchivedwebapplication.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4andRecipe22.5onpackagingataglibraryinawebapplication;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.13andRecipe22.14onpackagingatagfileandusingitinaJSP;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.13PackagingtheJSPTagFileinaJAR
Problem
YouwanttostorethetagfileinaJARfile.
Solution
PlacethetagfileintheJAR'sMETA-INF/tagsdirectoryorasubdirectorythereof.
Discussion
DeveloperscommonlydistributetaglibrariesasJARfiles,particularlyiftheyhavedesignedthetaglibrarytobeportable.ForJSP2.0-styletaglibrariesthatareusingtagfiles,placethetagfileinMETA-INF/tagsorasubdirectoryofMETA-INF/tags.Thetagfilemusthavea.tagextension,ora.tagxextensionifit'satagfileinXMLsyntax.
ThenplacetheJARfileinWEB-INF/libofanywebapplicationcontainingJSPsthatwillusethetag.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4andRecipe22.5onpackagingataglibraryinawebapplication;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7
onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.14onusingatagtagfilebasedonatagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.14UsingaCustomTagAssociatedwithaTagFile
Problem
Youwanttouseacustomtagassociatedwithatagfile.
Solution
UsethetaglibdirectiveintheJSP,beforethecodethatusesthetagfilerelatedtag.
Discussion
Thetaglibdirectiveidentifiesthetagwithitstagdirattribute,whichisthewebapplicationpathtothetagsdirectory.Example22-10usesthetagfromatagfilestoredat/WEB-INF/tags/logo.tag.
ThetagnameintheJSPisthesameasthetagfilename,withoutthe.tagextension.Theprefixattributerepresentsthecustomtag'snamespace,sotheentiretagisusedintheJSPas"<cbck:logoheading=...>...tagcontent...</cbck:logo>."
Example22-10.AJSPusesatagdefinedinatagfile
<%@taglibprefix="cbck"tagdir="/WEB-INF/tags"%>
<html>
<head><title>MeCasaSuCasa</title></head>
<body>
<%session.setAttribute("imgDir",(request.getContextPath()+"/images/"));%>
<cbck:logoheading="<%=request.getParameter(\"level\")%>"image=
"stamp.gif"width="42"height="54">
Thanksforvisitinghere...
</cbck:logo>
Here'salltheotherstuffthispagecontains...
</body>
</html>
Iusethesamebasiclogotagthroughoutthischaptertoillustratethevariouscustom-tagsyntaxdifferences.SeeRecipe22.2fordetailsonthelogotagitself.
SeeAlso
TheJSP2.0specificationwebpage:http://jcp.org/en/jsr/detail?id=152;Recipe22.2andRecipe22.3oncreatingTLDfilesfortaglibraries;Recipe22.4andRecipe22.5onpackagingataglibraryinawebapplication;Recipe22.6onusingthecustomtaginaJSP;Recipe22.7onhandlingexceptionsintags;Recipe22.8andRecipe22.9oncreatingasimpletaghandler;Recipe22.10onusingthesimpletaghandlerinaJSP;Recipe22.11-Recipe22.13onsettingupaJSPtagfile;Recipe22.15onaddingalistenerclasstoataglibrary;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Recipe22.15AddingaListenerClasstoaTagLibrary
Problem
Youwanttoincludealistenerclasswithyourtaglibrary.
Solution
AddalistenerelementtoyourTLDfile.
Discussion
TheservletAPIincludes"applicationeventlisteners,"whicharespecialJavaclassesthatarenotifiedbythewebcontainerwhencertaineventsoccur,suchasthecreationofanewusersession(seeChapter11).Youcanincludelistenerclasseswithyourtaglibraries.Forexample,youmighthaveasession-relatedtagthatneedstoknowwhensessionsarecreatedordestroyed.
Thelistenerelementhasexactlythesamesyntaxasitmayappearintheweb.xmldeploymentdescriptor.Example22-11showsalistenerelementincludedinaJSPVersion2.0TLD.
Example22-11.AddingalistenerelementtoaJSP2.0TLD
<!--beginningoftheTLDfile.Thelistenerelementisnestedinthetaglibelement.SEE
CHAPTER11OR14FORLISTENERCODEEXAMPLES-->
<taglibxmlns="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-jsptaglibrary_2_0.xsd"
version="2.0"
>
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>cbck</short-name>
<uri>com.jspservletcookbook.tags</uri>
<description>Cookbookcustomtags</description>
<listener>
<listener-class>
com.jspservletcookbook.ReqListener
</listener-class>
</listener>
<tag>
<!--declareataghere.SeeExample22-2(Recipe22.2),Example22-3(recipe
22.3),or22-7(Recipe22.9)-->
</tag>
</taglib>
TheJSPspecificationrequirestheJSPcontainertoautomaticallyinstantiateandregisterthelistenersthatareassociatedwithtaglibraries.Alistenercanbeusedwithataglibrarytotrackthenumberofrequeststhewebapplicationisreceiving,asshownintheServletRequestListenerinExample18-8(Recipe18.6).
JSP1.2'sTLDfileusesanXMLDTD.Therefore,theTLDelementsmustappearinaspecificsequence.Thelistenerelementisnestedinsidethetaglibelement;listenerappearsafteralloftheothernestedelementsexceptfortag.Youcanprecedeyourtagelementswiththelistenerelement.IntheJSP2.0TLD,ontheotherhand,youcanpositionthelistenerrightafterthetaglibrootelement.
StoreanylistenerclassesinthesameJARfileastheonecontaininganytaghandlerclasses.
Makesuretospecifythelistenerclassinthelistener-classelementasafullyqualifiedclassname,ortheJSPcontainerwillprobablyhavetroublefindingtheclass.
SeeAlso
Example18-8inRecipe18.6foranexampleofaclassthatimplementsthejavax.servlet.ServletRequestListener;Chapter11andChapter14forseverallistener-relatedrecipes;Recipe22.2oncreatingaJSP1.2TLDfile;Recipe22.3oncreatingaJSP2.0TLD;Recipe22.9oncreatingaTLDforasimpletaghandler;thecustomtagsectionsofHansBergsten'sJavaServerPages,ThirdEdition(O'Reilly).
Chapter23.UsingtheJSTLIntroduction
Recipe23.1.DownloadingtheJSTL1.0andUsingtheJSTLTagsinJSPs
Recipe23.2.DownloadingtheJavaWebServicesDeveloperPack
Recipe23.3.UsingtheCoreJSTLTags
Recipe23.4.UsingtheXMLCoreJSTLTags
Recipe23.5.UsingtheXMLTransformTags
Recipe23.6.UsingtheFormattingJSTLTags
Recipe23.7.UsingASQLJSTLTagwithaDataSourceConfiguration
Recipe23.8.UsingASQLJSTLTagWithoutaDataSourceConfiguration
Recipe23.9.AccessingScopedVariableswiththeEL
Recipe23.10.AccessingRequestParameterswiththeEL
Recipe23.11.UsingtheELtoAccessRequestHeaders
Recipe23.12.UsingtheELtoAccessOneRequestHeader
Recipe23.13.AccessingCookieswiththeEL
Recipe23.14.UsingtheELtoAccessJavaBeanProperties
Recipe23.15.UsingJSTLFunctions
Introduction
JavaServerPage'scustomtagsandtaghandlersaredesignedtohelpyouinventyourowntags.WhilethisisapowerfultoolforJavawebdevelopers,developingcustomtagsentailsasteeplearningcurveandcanbetimeconsuming.Luckily,somehard-workingvolunteersoftwaredevelopershavedevelopedabunchofhighlyusefultagsforyou.ThistagcollectioniscalledtheJavaServerPagesStandardTagLibrary(JSTL).TheJSTLspecificationarisesfromtheJavaCommunityProcess(JSR-052)andtheApacheJakartaProjecthasdevelopedaJSTLimplementation,theStandard1.0taglib.
TheJSTLhasverybroadfunctionality.Itincludestagsthat:
1. Setobjectattributesforwebapplications(c:set).
Outputtexttowebpages(c:outandx:out).
Iterateovercollectionsofdata(c:forEachandx:forEach).
Formatnumbers,dates,andcurrenciesusingdifferentinternationalstyles(e.g.,fmt:formatDate,fmt:formatNumber).
TransformXML(x:transform).
InteractwithdatabasesusingSQL(e.g.,sql:query,sql:update).
AllowyoutoembedfunctioncallsinJSPcodeandtemplatetext(e.g.,fn:substring()).ThisfunctionalityisavailableonlywithJSP2.0andJSTL1.1(seeRecipe23.14).
TheJSTLoriginatedaveryimportantnewJSPtechnology,theExpressionLanguage(EL).ThisisascriptinglanguagebasedgenerallyonJavaScriptandotherscriptingtoolsthat,withJSP2.0,canbe
embeddedinHTMLtemplatetext.
TheELwasoncepartofJSTL1.0buthasnowmigratedtotheJSPspecification.TheELmustbeimplementedwithJSP2.0containerssuchasTomcat5.
ThischapterisdesignedtostartyouquicklywiththeJSTL,whichcommonlyhastobedownloadedandinstalledinawebapplication.ManywebcontainerseventuallyintegrateorhavealreadyintegratedaJSTLimplementationwiththeirservletandJSPengines.
Recipe23.1DownloadingtheJSTL1.0andUsingtheJSTLTagsinJSPs
Problem
YouwanttodownloadandusetheJSTL.
Solution
DownloadtheJSTLdistribution,inaZIPorTARfile,fromtheApacheJakartaProject.
Discussion
TheApacheJakartaProjecthoststhereferenceimplementation(RI)fortheJSTL.AnRIissoftwarethatisdesignedtoimplementaparticularJavatechnologyspecificationinordertodemonstratehowthesoftwareisintendedtofunction.RIsarefreelyavailableforusebysoftwarevendorsanddevelopers.YoucandownloadthebinaryorsourcedistributionoftheJSTLfromhttp://jakarta.apache.org/taglibs/doc/standard-doc/intro.html.
UnpacktheZIPorTARfileintothedirectoryofyourchoice.Thiscreatesajakarta-taglibsdirectory.
ThisrecipeusestheStandardTaglibVersion1.0.3,animplementationoftheJSTL1.0.However,bythetimeyoureadthis,theJakartaTaglibssitewillhaveintroducedStandardTaglibVersion1.1,whichisanimplementationoftheJSTL1.1.Thenewversionincludessomenewfeaturessuchasfunctions,whicharedescribedinRecipe23.14.
Insidethestandard-1.0.3directoryisalibsubdirectory.ThisdirectorycontainsanumberofJARfiles,includingjstl.jarandstandard.jar.Thejstl.jarcontainstheJSTL1.0APIclasses;standard.jarisacollectionofJSTL1.0implementationclasses.AddalloftheJARfilesfoundinyourJSTLdistribution'slibdirectory(jakarta-taglibs/standard-1.0.3/libintheexample)toWEB-INF/lib.
JSTL1.1onlyrequirestheinstallationofjstl.jarandstandard.jarin/WEB-INF/libifyouareusingJ2SE1.4.2orhigher(aswellasServlet2.4andJSP2.0).
Table23-1describeseachoftheJARfilesfoundinthedistribution'slibdirectory(courtesyoftheStandardTaglib1.0documentation).
Table23-1.ContentsoftheJSTL1.0referenceimplementationlibdirectory
Filename Purpose
jstl.jar JSTL1.0APIclasses
standard.jar JSTL1.0implementationclasses
jaxen_full.jar Xpathengineclasses
jdbc2_0-stdext.jar JavaDatabaseConnectivity(JDBC)implementationclasses(alsoincludedwithJ2SE1.4)
saxpath.jar SimpleAPIforXpathparsing
xalan.jar ApacheXalanExtensibleStyleSheetTransformations(XSLT)processor
dom.jar,jaxp-api.jar,sax.jar,xercesImpl.jar JavaAPIforXMLProcessing(JAXP)1.2APIlibraries
IntheJSPwhereyouwanttousetheJSTLtags,usethepropertaglibdirectiveshowninTable23-2.Forexample,ifyouuseallofthedifferentJSTLfunctions(core,XML,formatting,andSQL),yourJSPcontainsallofthefollowingtaglibdirectives,preferablyatthetopoftheJSPpage(theymustappearbeforethetagsareused).
Table23-2.ThetaglibdirectivesfordifferentJSTLfunctions,version1.0
JSTLlibrary taglibdirective
Core <%@tagliburi="java.sun.com/jstl/core"prefix="c"%>
XMLprocessing <%@tagliburi="java.sun.com/jstl/xml"prefix="x"%>
Formattingdata(suchasdatesandcurrencies)forinternationalusers
<%@tagliburi="java.sun.com/jstl/fmt"prefix="fmt"%>
SQLandDatabaseaccess <%@tagliburi="java.sun.com/jstl/sql"prefix="sql"%>
TheJavacommunityisnowworkingontheJSTLVersion1.1,whichwillrequireaJSP-2.0compatibleJSPcontainer.JSTL1.1willusethesedifferenturivaluesinthetaglibdirective:
http://java.sun.com/jsp/jstl/core,sotheentiretaglibdirectivewouldlooklike:<%@tagliburi="java.sun.com/jsp/jstl/core"prefix="c"%>
http://java.sun.com/jsp/jstl/xml,creatingataglibdirectiveof:<%@tagliburi="java.sun.com/jsp/jstl/xml"prefix="x"%>
http://java.sun.com/jsp/jstl/fmt,asusedinthetaglibdirective:<%@tagliburi="java.sun.com/jsp/jstl/fmt"prefix="fmt"%>
http://java.sun.com/jsp/jstl/sql,creatingataglibdirectiveof:<%@tagliburi="java.sun.com/jsp/jstl/sql"prefix="sql"%>
SeeAlso
TheJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;SunMicrosystem'sJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.4andRecipe23.5onusingXML-relatedtags;Recipe23.6onusingtheformattingtags;Recipe23.7andRecipe23.8ontheJSTL'sSQLfeatures;Recipe23.9-Recipe23.14onusingtheELtoaccessscopedvariables,cookies,andJavaBeanproperties.
Recipe23.2DownloadingtheJavaWebServicesDeveloperPack
Problem
YouwanttodownloadtheJavaWebServicesDeveloperPack(WSDP)sothatyoucanuseaJSTL1.1referenceimplementation.
Solution
VisittheSunMicrosystemsJavaWSDPdownloadsiteathttp://java.sun.com/webservices/jwsdp.
Discussion
TheJavaWSDPVersion1.2containsreferenceimplementationsoftheJSTL1.1,aswellasseveralotherwebtiertechnologies,includingtheServletAPI2.4andJSP2.0.TheWSDPisbundledwithTomcat5,soonceyouinstalltheWSDPyoucanexperimentwiththevarioustechnologies,includingJavaServerFaces,JavaArchitectureforXMLBinding(JAXB),JavaAPIforXMLProcessing,andJavaAPIforXML-basedRPC(Jax-RPC).
TheJavaWSDP1.2installsonbothWindowsandvariousUnixsystems,suchasSolarisandLinux.Recipe23.15showshowtouseJSTL1.1functions;IusetheWSDPforthisrecipe.
UsingTomcat5andthenewJSTL1.1featuressuchasfunctionsandtheembeddingofELcodeintemplatetextrequiresyoutousetheservletAPI2.4versionofweb.xml.SeeRecipe23.15formoredetailsonthisissue.
SeeAlso
TheSunMicrosystemsJavaWSDPdownloadsiteat:http://java.sun.com/webservices/jwsdp;Recipe23.15onusingJSTL1.1functions;Sun'sJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.4andRecipe23.5onusingXML-relatedtags;Recipe23.6onusingtheformattingtags;Recipe23.7andRecipe23.8ontheJSTL'sSQLfeatures;Recipe23.9-Recipe23.14onusingtheELtoaccessscopedvariables,cookies,andJavaBeanproperties.
Recipe23.3UsingtheCoreJSTLTags
Problem
YouwanttousethecoreJSTLtagsinaJSP.
Solution
UsethetaglibdirectivewiththecoreuriattributevaluetomakethetagsavailableintheJSP.
Discussion
ThisrecipedemonstratesseveralJSTLtagsthatyouuseallthetime:c:set,c:out,c:forEach,andc:if.Herearethetagsummaries:
Thec:settagsetsobjectattributestopage,request,session,orapplicationscopes.
Thec:outtagdisplaystextliteralsorthevaluesofvariablesorbeanpropertiesinyourJSPs.
Thec:forEachtagiteratesoverMaps,Collections,andarrays.
Thec:iftagtestsexpressionsfortrueorfalsevalues,thenconditionallyexecutesthecodenestedinthec:ifbody.
RemembertousetheprefixforthecertainfunctionalareaoftheJSTL,suchasc,
followedbyacolon,andthetagname,asin"c:forEach."
Example23-1isahelperclassthatIfindnecessarytoproperlyreturnaStringarrayofTimeZoneIDstotheJSPinExample23-2.
Example23-1.AhelperclasstohelpdisplayTimeZoneIDs
packagecom.jspservletcookbook;
importjava.util.TimeZone;
publicclassZoneWrapper{
publicZoneWrapper(){}
publicString[]getAvailableIDs(){
returnTimeZone.getAvailableIDs();
}
}
Example23-2showshowtouseanumberofthecoreJSTLtags.Thecodeusesthejsp:useBeanstandardactiontocreateZoneWrapper(Example23-1)andjava.util.Dateobjectsforusebythetags.
Example23-2.UsingcoreJSTL1.0tagsinaJSP
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="zone"class="com.jspservletcookbook.ZoneWrapper"/>
<jsp:useBeanid="date"class="java.util.Date"/>
<html>
<head><title>UsingtheCoreJSTLtags</title></head>
<body>
<h2>HerearetheavailableTimeZoneIDsonyoursystem</h2>
<c:iftest="${date.time!=0}">
<c:outvalue=
"Phew,timehasnotstoppedyet...<br/><br/>"escapeXml="false"/>
</c:if>
<%--Thevariable'zones'containsaStringarrayofTimeZoneIDs;itisstoredasa
'session'objectattribute.The'${zone.availableIDs}'expressionistheequivalentof
callingtheZoneWrapper.getAvailableIDs()method--%>
<c:setvar="zones"value="${zone.availableIDs}"scope="session"/>
<c:forEachvar="id"items="${zones}">
<c:outvalue="${id}<br/>"escapeXml="false"/>
</c:forEach>
</body>
</html>
Thec:iftagusesanELphrasetotestwhethertheDateobject'sgetTime()methodreturnsavaluethatisnotzero(ofcourseitdoes!I'mjustdemonstratinghowtousethec:iftag).
${date.time!=0}
ThepriorcoderepresentsabooleanexpressionthatreturnstrueifDate.getTime()isgreaterthanzero.Iftrue,thenthecodeexecutesthenestedc:outtag,whichwritesamessagethattheclient'sbrowserdisplays.
TheescapeXml="false"codedisplaysthecharacters<br/><br/>correctlyintheHTMLoutputbythec:outtag.SeeTable23-3.
Example23-2setsanobjectattributetosessionscope.ThisobjectisaString[]typecontainingtimezoneIDs,suchas"Pacific/Tahiti."Thec:forEachtagtheniteratesoverallofthesearraymembers,displayingeachIDwiththec:outtag:
<c:forEachvar="id"items="${zones}">
<c:outvalue="${id}<br/>"escapeXml="false"/>
</c:forEach>
Thevarattributeofthec:forEachtagstoresthecurrentarraymemberasc:forEachcyclesoverthecollection.Thec:outtagusesanELexpressiontoaccessthevalueofthecurrentarraymember:
<c:outvalue="${id}<br/>"escapeXml="false"/>
IfyoudonotgivetheescapeXmlattributeafalsevaluewhenusingc:out,thecharacterentitycodesshowninTable23-3willdisplayinsteadoftheescapedcharacters.
Table23-3.Thec:outtag'sescapedcharacters
c:outvalueattributecharacter Characterentitycode
< <
> >
& &
` '
" "
Figure23-1showsapartoftheJSPusingthecodeinExample23-2.
Figure23-1.AJSPusingthevariouscoretagstodisplaytimezoneIDs
SeeAlso
Recipe6.8onincludingcontentinaJSPwiththec:urltag;theJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;theSunMicrosystemsJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.4andRecipe23.5onusingXML-relatedtags;Recipe23.6onusingtheformattingtags;Recipe23.7andRecipe23.8ontheJSTL'sSQLfeatures;Recipe23.9-Recipe23.14onusingtheELtoaccessscopedvariables,cookies,andJavaBeanproperties.
Recipe23.4UsingtheXMLCoreJSTLTags
Problem
YouwanttousetheJSTL'sXMLtagsinaJSP.
Solution
UsethevariousXMLtagsafterdeclaringthetaglibrarywiththepropertaglibdirective(uriattributeofhttp://java.sun.com/jstl/xmlforJSTL1.0orhttp://java.sun.com/jsp/jstl/xmlforJSTL1.1).
Discussion
ManywebdevelopershavetowriteprogramsthatparseorreadXMLtofindinformation,ortheyhavetowritecodethatdisplaystheencapsulatedXMLinformationinareadableformat.TheJSTLXMLtagsareanicetoolforthesetasks.Example23-3displayssomeinformationfromanAntbuild.xmlfile.(SeeChapter4ontheAnttoolifyouarenewtoAnt.)I'musingthisXMLfilejustforanexampleofhowtousetheXML-relatedJSTLtags.NoticethatthetaglibdirectivesatthetopofthepageallowtheuseoftheXMLandcoreJSTLtagsfurtheralonginthecode.
Example23-3.AJSPparsesanantbuildfile
<%@tagliburi="http://java.sun.com/jstl/xml"prefix="x"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>UsingtheCoreXMLtags</title></head>
<body>
<h2>HerearethetargetandpropertyvaluesfromtheXMLfile</h2>
<c:importurl="http://localhost:8080/home/build.xml"var="buildXml"/>
<x:parsexml="${buildXml}"var="antDoc"/>
<h3>Firstthetargetnames...</h3>
<x:forEachselect="$antDoc/project/target">
<x:outselect="@name"/>
<x:ifselect="@depends">:depends=<x:outselect="@depends"/></x:if><br/>
</x:forEach>
<h3>Thenpropertynamesandvalues...</h3>
<x:forEachselect="$antDoc/project/target/property">
<x:outselect="@name"/>:value=<x:outselect="@value"/><br/>
</x:forEach>
</body>
</html>
Example23-3usesthec:importtagtoimportabuildfileandstoreitinavariablecalledbuildXml.Thethex:parsetagthenparsestheimporteddocumentintoaformorobjectthattheotherXMLtagscanworkwith.ThecodestorestheparsingresultinanothervariablenamedantDoc.
TheXMLJSTLtagsusesomeofthesametagnamesasthecorelibrary,butadifferentprefix("x").Thex:forEachtaginExample23-3usesanXPathexpressionasthevalueofthex:forEachselectattribute.
XPathisanXMLtechnologythatisdesignedtosearchforandselectportionsor"nodesets"ofthehierarchicaltreerepresentedbyanXMLdocument.WhileanXPathtutorialiswellbeyondthescopeofthisrecipe(itislikealittleprogramminglanguageinitself),thereareplentyofonlinetutorialsandbooksonthesubject.YoucanstartattheSunMicrosystemswebservicestutorial,whichincludesadiscussionofXPath:http://java.sun.com/webservices/docs/1.3/tutorial/doc/.
Thex:forEachtagmakesnestedelementssuchasx:outavailabletoanynodesgrabbedbytheXPathexpression.ThecodeinExample23-3displaysthenameofeachAnttargetinthebuild.xmlfilebyfirstcollectingasetofallofthetargetelementswiththisexpression:
<%--thisXPathexpressionistheequivalentof"beginattheroot'project'element
andgetallofitsnested'target'elements"--%>
<x:forEachselect="$antDoc/project/target">
Example23-3outputsthenameofeachtargetwiththiscode:
<x:outselect="@name"/>
Theenclosingx:forEachtagestablishesthecontextoftheXPathexpressioninthisx:outtag.
Thefollowingcodestates"returntrueifthecurrentnodehasavaliddependsattribute."
<x:ifselect="@depends">
Ifthatexpressionreturnstrue,thenestedx:outtagoutputsthevalueofthedependsattribute.Figure23-2showstheresultofrequestingtheJSPofExample23-3inabrowser.I'veconvertedtheXMLinformation
intoamorereadableformatforabrowser.XMLmavens(meaningthosewhocansiftthroughallofthesecrazyacronyms!)declarethatyoucanalsouseExtensibleStylesheetLanguageTransformations(XSLT)forconvertingXMLinformationtoHTMLorotherreadableforms.Thisisthenextrecipe'stopic.
Figure23-2.AJSPshowstheoutputofaparsedXMLfile
SeeAlso
TheJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;SunMicrosystem'sJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.5onusingtheXMLTransformtags;Recipe23.6onusingtheformattingtags;Recipe23.7andRecipe23.8ontheJSTL'sSQLfeatures;Recipe23.9-Recipe23.14onusingtheELtoaccessscopedvariables,cookies,andJavaBeanproperties.
Recipe23.5UsingtheXMLTransformTags
Problem
YouwanttousetheJSTL'sXMLandXSLT-relatedtags.
Solution
UsethevariousXMLtagsafterdeclaringthetaglibrarywiththepropertaglibdirective(uriattributeofhttp://java.sun.com/jstl/xmlforJSTL1.0orhttp://java.sun.com/jsp/jstl/xmlforJSTL1.1).
Discussion
AnumberofwebsiteteamsmayalreadyhavedevisedstylesheetsfortransformingXMLintoHTML.Inaddition,youmaywanttoseparatemostoftheXMLtransformationresponsibilitiesfromJSPs,sothatJSPsfocusonlyonpresentingthetransformedinformation.TheJSTLprovidesXML-relatedtagstoeasilyintegratestylesheetsintoJSPs.Example23-4isanExtensibleStylesheetLanguage(XSL)documentthatconvertsanXMLfileintoHTML.ThestylesheetprovidesaconversionofanAntbuildfilesimilartotheonedescribedinRecipe23.3.
Example23-4.ThestylesheetfortransforminganXMLfile
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<xsl:stylesheetxmlns:xsl="http://www.w3.org/1999/XSL/Transform"version="1.0">
<xsl:outputmethod="html"/>
<xsl:templatematch="/">
<html><head><title>Listofbuild.xmltargets
</title></head><bodybgcolor="white"><h2>Build.xmltargets</h2>
<xsl:apply-templates/>
</body></html>
</xsl:template>
<xsl:templatematch="/project">
<dl>
<xsl:for-eachselect="./target">
<dt><b>
<xsl:value-ofselect="@name"/></b> </dt>
<xsl:iftest="@depends">
<dd>depends=<xsl:value-ofselect="@depends"/> </dd>
</xsl:if>
</xsl:for-each><!--endfor-each-->
</dl>
</xsl:template>
<xsl:templatematch="text()">
<xsl:value-ofselect="normalize-space()"/>
</xsl:template>
</xsl:stylesheet>
HowdoyouapplythisXSLfiletothebuild.xmlfiletoproduceareadable
format?Example23-5usesthex:transformtagtoassociateastylesheetwithanXMLfile.First,theJSPhastoimportboththestylesheetofthepriorexampleandtheXMLfilethisstylesheettransformsbyusingthec:importtag.Thec:importtagimportstheresourcespecifiedbyitsurlattributeandstoresitinavariable(e.g.,buildXml)thatthex:transformtagcanaccess.
Example23-5.AJSPdisplaystheresultofanXSLtransformation
<%@tagliburi="http://java.sun.com/jstl/xml"prefix="x"%>
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<c:importurl="http://localhost:8080/home/build.xml"var="buildXml"/>
<c:importurl="/WEB-INF/xslt/chap23.xsl"var="xslt"/>
<x:transformxml="${buildXml}"xslt="${xslt}"/>
Thex:transformtagmakesthetransformationprocessveryeasy,onceyou'veputtogetheravalidstylesheetfile.Thex:transformtag'sxmlattributespecifiestheXMLfilethatthex:transformtaghandlertransformsbyapplyingastylesheet.Thecodespecifiesthestylesheettouseinthetransformationwiththex:transformtag'sxsltattribute.
Thexmlandxsltattributesofx:transformresolvethevariablesthatrepresentthestylesheetandtheXMLfilebyusingtheEL,asin:
${buildXml}
Figure23-3showstheresultofrunningtheJSPofExample23-5.Inshort,x:transformprovidesyourveryownXSLTprocessorforuseintheJSP.
Figure23-3.AJSPshowstransformedXMLcontent
SeeAlso
TheJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;theSunMicrosystemsJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.2onusingthecoretags;Recipe23.3onusingthevariousXML-relatedtags;Recipe23.5onusingtheformattingtags;Recipe23.6andRecipe23.7ontheJSTL'sSQLfeatures;Recipe23.9-Recipe23.14onusingtheELtoaccessscopedvariables,requestheadersandparameters,cookies,andJavaBeanproperties.
Recipe23.6UsingtheFormattingJSTLTags
Problem
YouwanttoformatadateoranumberusingtheJSTL.
Solution
Usethefmt:formatDateandfmt:formatNumberactions.
Discussion
Internationalizationor"i18n"istheprocessbywhichwebdevelopersdesigntheirwebsitestoaccommodatevisitorswhousedifferentlanguages.
Theterm"i18n"meansinternationalizationbeginswith"i,"isfollowedby18letters,andendswith"n."Itisdesignedtorelievethetediumofspellingoutthewordseveraltimes.
Localizationmeansaddingspecificresourcestoawebsitetoenablemessagessuchaswebpagegreetingstobetranslatedintothevisitor'slanguage.Forexample,youmightlocalizeasiteforJapanesevisitorsbyaddingresourcesthatcontainJapanesetranslationsoftextthatappearsonwebpages(Icovermorei18n-relatedJavacodeinChapter24).Example23-6usestheJSTLformattingtaglibrarytodisplaythecurrentdateandalargenumberinSwissandU.S.styles.
Example23-6.showingadateandanumberforU.S.andSwissaudiences
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%--includethistaglibfori18nrelatedactions--%>
<%@tagliburi="http://java.sun.com/jstl/fmt"prefix="fmt"%>
<html>
<head><title>Formattingnumbersanddates</title></head>
<body>
<h2>DatesandnumbersinSwissandUSstyleformats</h2>
<%--createanobjectrepresentingthecurrentdate--%>
<jsp:useBeanid="now"class="java.util.Date"/>
<%--setthelocaletoGermanlanguage,Swisscountrycode--%>
<fmt:setLocalevalue="de_CH"/>
<strong>Swiss-styledate:</strong>
<%--outputthedate--%>
<fmt:formatDatetype=
"both"value="${now}"dateStyle="full"timeStyle="short"/>
<br/>
<strong>Swiss-stylenumber:</strong>
<%--outputtheequivalentofjava.util.Date.getTime()toshowhownumbersareformatted
--%>
<fmt:formatNumbervalue="${now.time}"/>
<br/><br/>
<%--resetthelocaletoEnglishlanguage,UScountrycode--%>
<fmt:setLocalevalue="en_US"/>
<strong>US-styledate:</strong>
<%--outputthedate--%>
<fmt:formatDatetype="both"value="${now}"dateStyle=
"full"timeStyle="short"/>
<br/>
<strong>US-stylenumber:</strong>
<fmt:formatNumbervalue="${now.time}"/>
<br/><br/>
</body>
</html>
Example23-6usesfmt:setLocaletosetthecontextforformattingdatesandnumbersfirsttoSwiss-German("de_CH"),thenbacktoU.S.English("en_US").
A"locale"representsaparticularcultural,geographic,orpoliticalregion.LocalesaretypicallyspecifiedbyaStringshowingalanguagecodefollowedbyanunderscore"_"andthecountrycode.SeeChapter24foranexpandeddiscussionofi18ntopics.
Bothfmt:formateDateandfmt:formatNumberusethecurrentlocaletoformattheirinformation.Thefmt:formateDatetaghasseveralattributesthataredesignedtoconfigurethedateformat.Thebothattributespecifieswhethertooutputonlythedate,thetime,orboththedateandtime,asinExample23-6.ThedateStyleandtimeStyleattributeshavesettingsthatderivefromthejava.text.DateFormat
class.Example23-6specifiesa"full"datedisplaythatincludesthedayofweek,themonth,andtheyear.Thecodealsospecifiesa"short"timedisplay(suchas"8:07").
Figure23-4showstheJSPthatformatsdatesandnumbersforSwiss-GermanandU.S.Englishspeakers.ThereareseveralotherformattingrelatedJSTLtags,whichtherecipesofChapter24coverinmoredetail.
Figure23-4.Thefmt:formatDateandfmt:formateNumbertagsperformtranslationmagicinaJSP
SeeAlso
Chapter24onusingtheJSTL'sseverali18n-relatedtags;theJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;theSunMicrosystemsJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.5onusingtheXMLTransformtags;Recipe23.7andRecipe23.8ontheJSTL'sSQLfeatures;Recipe23.9-Recipe23.14onusingtheELtoaccessscopedvariables,cookies,andJavaBeanproperties.
Recipe23.7UsingASQLJSTLTagwithaDataSourceConfiguration
Problem
Youwanttointeractwitharelationaldatabasebyconfiguringthejavax.sql.DataSourceinthedeploymentdescriptor.
Solution
Addacontext-paramelementtoweb.xml,creatingaparameternamedjavax.servlet.jsp.jstl.sql.dataSourcethatconnectswithaparticulardatabase.
Discussion
TheJSTLSQLtaglibraryallowsaJSPtointeractwithadatabaseusingcustomtags.JavaDatabaseConnectivity(JDBC)andtheclassesinthejavax.sqlpackageallowthistechnologytowork.ThefirststepinthisrecipeistoconfiguretheDataSourcethatthetagswillusetoconnectwithadatabase.
ADataSourceisafactoryforjava.sql.Connectionobjects,whichrepresentasocketconnectionwithaparticulardatabaseserversuchasMySQLorOracle.
Example23-7createsacontext-paramelementinweb.xml.Forthe
JSTL'sSQLtagstoautomaticallyreceivetheirConnectionsfromthissetting,theparamnamemustbejavax.servlet.jsp.jstl.sql.dataSource.Theparamvaluecomprisescomma-separatedphrases:
[JDBCURL],[Drivername],[user],[password]
DeveloperscommonlyderivetheJDBCURLanddrivernamefromdatabasevendordocumentation(andoftenfrommailinglists,becausedebuggingbackenddatabaseconnectionswithJDBCcanbetricky!).ThecodeIshowherecontainsanexampleofaJDBCURLforOracle8iPersonalEdition.
Example23-7.Anexampleweb.xmlconfigurationforajavax.sql.Datasource
<!--topofweb.xmlfile-->
<context-param>
<param-name>javax.servlet.jsp.jstl.sql.dataSource</param-name>
<param-value>jdbc:oracle:thin:@192.168.0.2:1521:ORCL,
oracle.jdbc.driver.OracleDriver,scott,tiger</param-value>
</context-param>
<!--restofweb.xmlfile-->
TheJSTLsoftwareusesthesevaluestogenerateaDataSourceforitsSQLtags.TheadvantageofusinganexternalsettingfortheDataSourceisthattoswitchdatabases,youcanchangethevalueofthecontext-paramtotheconfigurationrepresentingthenewdatabasewithouttouchingtheJSPcode.TheJSPdealstransparentlywiththeSQLtagsandDataSourceobject.
NowontotheJSP.RememberthattheSQLtags(theonesusingthe"sql"prefix)usetheDataSourcethatwejustsetwiththecontext-paramelementinweb.xml.
Webapplicationsalwayshaveaweb.xmlfileintheWEB-INFdirectory.SeeChapter1ifyouneedafurtherexplanation.
ThetaglibdirectivesatthetopofExample23-8arerequiredifyouwanttousetheJSTL1.0coreandSQLlibraries.
Example23-8.AJSPusesJSTLsqltagstodisplaydatabaseinformation
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%@tagliburi="http://java.sun.com/jstl/sql"prefix="sql"%>
<html>
<head><title>DatabaseQuery</title></head>
<body>
<h2>QueryingadatabasefromaJSTLtag</h2>
<sql:queryvar="athletes">
SELECT*FROMathlete
</sql:query>
<tableborder="1">
<c:forEachvar="row"items="${athletes.rows}">
<tr>
<th>user_id</th>
<th>name</th>
<th>birthdate</th>
<th>passwrd</th>
<th>gender</th></tr>
<tr>
<td><c:outvalue="${row.user_id}"/></td>
<td><c:outvalue="${row.name}"/></td>
<td><c:outvalue="${row.birthdate}"/></td>
<td><c:outvalue="${row.passwrd}"/></td>
<td><c:outvalue="${row.gender}"/></td>
</tr>
</c:forEach>
</table>
</body>
</html>
Thesql:querytagusesitsnestedcontenttosendtheSQLSELECTstatement"select*fromathlete"toadatabase.ThedatabaseconnectionderivesfromtheDataSourceyouhavealreadyconfigured.Thestatementisdesignedto"selectallrowsfromthetablenamed`athlete.'"Thesql:querytagsavestheresultsetinajavax.servlet.jsp.jstl.sql.Resultobject,inavariablenamedathletes.
Resultobjectsareconvertedfromjava.sql.ResultSetobjects.Resultobjectshavemethods(suchasgetRows())thataredesignedtointeractwiththeJSTLSQLtags.
Thecode:
${athletes.rows}
isanELphrasethatcallstheResultobject'sgetRows()method.Thismethodreturnsajava.util.SortedMap[]typeoranarrayofSortedMaps.Example23-8usesthec:forEachtagtoiterateoverthisarrayandcreateanHTMLtablerowoutofeachofthereturneddatabaserows.
Youcanusethisformofcodetodisplaythecolumnnamesofaresultset(`athletes'isthevariablestoringtheresultset):
<c:forEachvar="col"items=
"${athletes.columnNames}">
<c:outvalue="${col}"/>
</c:forEach>
ThenextrecipeshowshowaJSPaccomplishesthissametaskwithoutacontext-paramconfiguringtheDataSource.
TrytostickwiththestrategyofsettingtheDataSourceinweb.xml,becauseitrepresentsabettersoftwaredesignthanclutteringupaJSPwithaDataSourceconfiguration.
Figure23-5showstheJSPdisplayingthedatabaserowinformationinawebbrowser.
Figure23-5.DisplayingdatabaseinformationinaJSP
SeeAlso
Chapter21onworkingwithdatabases;theJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;theSunMicrosystemsJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.5onusingtheXMLTransformtags;Recipe23.6onusingtheformattingtags;Recipe23.8onusingaSQLJSTLtagwithoutaDataSourceconfiguration;Recipe23.9-Recipe23.14onusingtheELtoaccessscopedvariables,cookies,andJavaBeanproperties.
Recipe23.8UsingASQLJSTLTagWithoutaDataSourceConfiguration
Problem
YouwanttospecifytheDataSourcefortheJSTLSQLtagsinsideaJSP.
Solution
Usethesql:setDataSourcetagtoestablishaDataSourcefortheotherSQLtags,suchassql:query.
Discussion
YoucanexplicitlysettheDataSourcefortheJSTLSQLtagsinaJSPusingsql:setDataSourceanditsdataSourceattribute.Example23-9createsthesameDataSourceasRecipe23.6andstoresitinavariablenameddSource.Thesql:querytagthenspecifiesthisDataSourcewithitsowndataSourceattribute.ThecodeotherwiseaccomplishesthesametaskasExample23-8:theJSPsendsaSELECTSQLstatementtothedatabasesystem,thendisplaystheresults.
Example23-9.Usingthesql:setDataSourcetag
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%@tagliburi="http://java.sun.com/jstl/sql"prefix="sql"%>
<html>
<head><title>DatabaseQuery</title></head>
<body>
<h2>QueryingadatabasefromaJSTLtag</h2>
<sql:setDataSourcedataSource=
"jdbc:oracle:thin:@192.168.0.2:1521:ORCL,oracle.jdbc.driver.OracleDriver,scott,tiger"
var="dSource"scope="application"/>
<sql:queryvar="athletes"dataSource="dSource">
SELECT*FROMathlete
</sql:query>
<tableborder="1">
<c:forEachvar="row"items="${athletes.rows}">
<tr>
<th>user_id</th>
<th>name</th>
<th>birthdate</th>
<th>passwrd</th>
<th>gender</th></tr>
<tr>
<td><c:outvalue="${row.user_id}"/></td>
<td><c:outvalue="${row.name}"/></td>
<td><c:outvalue="${row.birthdate}"/></td>
<td><c:outvalue="${row.passwrd}"/></td>
<td><c:outvalue="${row.gender}"/></td>
</tr>
</c:forEach>
</table>
</body>
</html>
ThecodestorestheDataSourceinanapplication-scopedvariable,sothatanotherJSPcanaccesstheDataSourcethisway:
<sql:queryvar="athletes"dataSource="${dSource}">
SELECT*FROMathlete
</sql:query>
Theonlydifferencebetweenthissql:queryusageandExample23-9isthatthevalueofthedataSourceattributehastoberesolvedusingtheEL;thetaghastofindandgetthevalueofanapplication-scopedvariable(aservletcontextattribute)named"dSource."
YoucanalsospecifyaDataSourceintheJSTLSQLtagsasaJavaNamingandDirectoryInterface(JNDI)string,butwewillreservediscussionofthattopicforChapter21,whichcoversusingdatabaseswithservletsandJSPs.
SeeAlso
Chapter21onworkingwithdatabases;theJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;theSunMicrosystemsJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.4andRecipe23.5onusingtheXMLtags;Recipe23.6onusingtheformattingtags;Recipe23.7andRecipe23.8onusingtheSQLJSTLtags;Recipe23.9-Recipe23.14onusingtheELtoaccessscopedvariables,cookies,andJavaBeanproperties.
Recipe23.9AccessingScopedVariableswiththeEL
Problem
YouwanttograbanddisplaythevalueofanobjectattributeusingaJSTLcustomtag.
Solution
UsetheELandthec:outtagtogetthevalueofanattributethathasbeenstoredinacertainscope.
Discussion
Anobjectsuchasajava.util.Date,ajava.lang.Integer,oranobjectthatyoudesign,canbestoredinfourdifferentscopes:
page,sothatit'sonlyavailableintheservletorJSPwhereitiscreated
requestscope,whichmakestheobjectavailabletoanypagesthatinteractwiththeJSPusingaRequestDispatcher,suchasarequestthatisforwardedfromoneJSPtoanother
sessionscopestoresobjectattributesforanyservletsorJSPsthatparticipateinthesamesession(seeChapter11)
applicationscope,whichrepresentstheentireservletcontextfor
onewebapplication
Example23-10usesthec:setJSTLtagtosetavariablenamedcom.jspservletcookbook.SessionObjecttosessionscope.Thenc:outaccessesanddisplaysthevalueofthevariable.
Example23-10.Accessingthevalueofanobjectstoredinsessionscope
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>AccessingaScopedValue</title></head>
<body>
<h2>HereisthevalueoftheSession-ScopedAttribute</h2>
<c:setvar=
"com.jspservletcookbook.SessionObject"value=
"Myobjectattribute.<br/>"scope="session"/>
<c:outvalue=
"${sessionScope[\"com.jspservletcookbook.SessionObject\"]}"escapeXml="false"/>
</body>
</html>
Byconvention,objectattributesarenamedafterfullyqualifiedJavaclasses(usually,aftertheJavatypeofthestoredobject).Therefore,theattributenamehasperiodcharacters(.)init.Thisisthepurposeofthesyntax${sessionScope[\"com.jspservletcookbook.SessionObject\"]}
Iftheattributenamedoesnotcontainperiods,thenyoucanuseanELexpressionconsistingofjustthevariablename,withoutthesessionScopeJSTLimplicitobject,inordertoaccesstheobjectattribute:
<c:outvalue=
"${SessionObject}"escapeXml="false"/>
Ifyoujustincludethescopedobject'sname,asinthepriorcodefragment,thentheJSTLwillsearchthepage,request,session,andapplicationscopesforanattributeofthatname,returningnulliftheJSTLdoesnotfindone.
YoumustusetherequiredcharactersofanELexpression(thedollarsignandcurlybracessurroundingtheexpression:"${...}").Otherwisethec:outtagwilljustoutputaStringliteralsuchas"SessionObject."
SeeAlso
TheJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;SunMicrosystem'sJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.4andRecipe23.5onusingtheXMLtags;Recipe23.6onusingtheformattingtags;Recipe23.7andRecipe23.8onusingtheSQLJSTLtags;Recipe23.10-Recipe23.14onusingtheELtoaccessrequestparameters,cookies,andJavaBeanproperties.
Recipe23.10AccessingRequestParameterswiththeEL
Problem
YouwanttoaccessarequestparameterusingtheELinaJSP.
Solution
UsetheparamimplicitobjectinyourJSPcode.
Discussion
TheJSTLprovidesanimplicitobjectnamedparamthatyoucanusetogetarequestparameter.Simplyfollowtheterm"param"withaperiodandtheparametername.UsethisterminologywiththeELtooutputthevalueofarequestparameterwiththec:outtag.Example23-11displaysagreetingwiththevisitor'sname.Therequestmightlooklike:
http://localhost:8080/home/welcome.jsp?name=Bruce%20Perry
IftheURLdoesnotincludethe"name"parameter,theJSPdisplaysthemessage"HelloEsteemedVisitor."
Example23-11.UsingtheJSTLinaJSPtodisplaytheresultofarequestparameter
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>AccessingaScopedValue</title></head>
<body>
<h2>Hello
<c:choose>
<c:whentest="${emptyparam.name}">
EsteemedVisitor
</c:when>
<c:otherwise>
<c:outvalue="${param.name}"/>
</c:otherwise>
</c:choose>
</h2>
</body>
</html>
ThecodetestswhethertherequestcontainsavaluefornamebyusingtheemptyELkeyword:
<c:whentest="${emptyparam.name}">
Thec:choose,c:when,andc:otherwisetagsarelikeif/then/elsestatementsinJavacode.Iftherequestparameternamedoesnothaveavalue,thebrowserwilldisplay"EsteemedVisitor".Otherwise,itdisplaysthevalueofname.
Figure23-6showsaJSPdisplayingthemessage,includingtheparametervalue.
Figure23-6.HumbleoutputofaJSPusingtheparamJSTLimplicitobject
SeeAlso
Chapter18onworkingwiththeclientrequest;theJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;SunMicrosystem'sJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.4andRecipe23.5onusingtheXMLtags;Recipe23.6onusingtheformattingtags;Recipe23.7andRecipe23.8onusingtheSQLJSTLtags;Recipe23.11-Recipe23.14onusingtheELtoaccessrequestheaders,cookies,andJavaBeanproperties.
Recipe23.11UsingtheELtoAccessRequestHeaders
Problem
YouwanttousetheELtoaccessthevalueofvariousHTTPrequestheaders.
Solution
UsetheheaderimplicitobjectthattheELmakesavailableforcustomtags.
Discussion
Theheaderimplicitobjectisajava.util.Maptypethatcontainsarequestheadervaluemappedtoeachheaderkey(whichistheheadername,suchas"accept"or"user-agent").Webclients(usuallybrowsers)sendtheseheadersorname/valuepairsalongwiththewebaddressofthepagetheyareinterestedin.
Example23-12usesthec:forEachiterationtagtocyclethrougheachoftheMap'sstoredrequestheaders.ThevariablereqHeadstoresthecurrentheader/valuepair.ThecodeusestheELtodisplaytheheadername("${reqHead.key}")andheadervalue("${reqHead.value}").
Example23-12.UsingtheJSTLtodisplayrequestheaders
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>Requestheaderdisplay</title></head>
<body>
<h2>HerearealltheRequestHeaders</h2>
<%--'header'representsajava.util.Maptypeholdingrequest-headernamesandvalues--%>
<c:forEachvar="reqHead"items="${header}">
<strong><c:outvalue=
"${reqHead.key}"/></strong>:<c:outvalue="${reqHead.value}"/><br/>
</c:forEach>
</body>
</html>
Figure23-7showstheresultofrequestingthisJSPinawebbrowser.
Figure23-7.DisplayingrequestheadersinaJSP
SeeAlso
Chapter18onworkingwiththeclientrequest;theJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;SunMicrosystem'sJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.4andRecipe23.5onusingtheXMLtags;Recipe23.6onusingtheformattingtags;Recipe23.4andRecipe23.5onusingtheSQLJSTLtags;Recipe23.12-Recipe23.14onusingtheELtoaccessonerequestheader,cookies,andJavaBeanproperties.
Recipe23.12UsingtheELtoAccessOneRequestHeader
Problem
YouwanttousetheELtoaccessthevalueofoneparticularHTTPrequestheader.
Solution
UsetheheaderValuesimplicitobjectthattheELmakesavailableforcustomtags.
Discussion
TheheaderValuesimplicitobjectisajava.util.MaptypethatcontainsaStringarray(aString[]type)foreveryheadername.Example23-13displaysonlythevalueofthe"user-agent"requestheader,whichidentifiesthetypeofbrowsertheclientisusing.
Example23-13.UsingtheJSTLtodisplayrequestheaders
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>UserAgent</title></head>
<body>
<h2>Hereisyouruseragent</h2>
<%--'headerValues'representsajava.util.MaptypeholdingaString[]typeforevery
requestheader--%>
<strong><c:outvalue=
"${headerValues[\"user-agent\"][0]}"/></strong>
</body>
</html>
ThecodeaccessesonlythefirstmemberoftheStringarray(itishighlylikelythattheuser-agentrequestheaderonlyinvolvesonevalue).Theexpression:
${headerValues[\"user-agent\"]}
returnsthearray,andtheentireexpression,includingthe"[0]"arrayoperator,whichreturnsthenameoftheuseragent,suchas"Mozilla/4.0(compatible;MSIE5.5;WindowsNT4.0)."
SeeAlso
Chapter18onworkingwiththeclientrequest;Recipe23.11onhowtousetheELtoaccessalltheavailablerequestheaders;theJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;theSunMicrosystemsJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.4andRecipe23.5onusingtheXMLtags;Recipe23.6onusingtheformattingtags;Recipe23.7andRecipe23.8onusingtheSQLJSTLtags;Recipe23.10onusingtheELtoaccessrequestparameters;Recipe23.13andRecipe23.14onusingtheELtoaccesscookiesandJavaBeanproperties.
Recipe23.13AccessingCookieswiththeEL
Problem
YouwanttotakealookatallofthecookienamesandvaluesusingELcode.
Solution
UsethecookieELimplicitobjectintheJSPtodisplayanycookienamesandvalues.
Discussion
ThecookieELimplicitobjectisajava.util.Maptypethatmapscookienames(like"JSESSIONID")tojavax.servlet.Cookieobjects.SincethecookiesarestoredinaMap,youcanusethec:forEachtagtocyclethroughthemapanddisplayeachcookienameandvalueusingc:out(seeExample23-14).
MakesuretoincludethetaglibdirectiveatthetopoftheJSPsothepagecanusethecoreJSTLtags.
Example23-14.usingtheELtodisplayeachcookienameandvalueinaJSP
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>Cookiedisplay</title></head>
<body>
<h2>HerearealltheAvailableCookies</h2>
<%--${cookies.key}equalsthecookiename;${cookies.value}equalstheCookieobject;
${cookies.value.value}returnsthecookievalue--%>
<c:forEachvar="cookies"items="${cookie}">
<strong>
<c:outvalue="${cookies.key}"/>
</strong>:Object=
<c:outvalue="${cookies.value}"/>,value=
<c:outvalue="${cookies.value.value}"/><br/>
</c:forEach>
</body>
</html>
Thec:forEachtagstorestheentryintheMapforeachcookieinavariablenamedcookies.ThecodeusestheELphrase"${cookies.key}"toaccessthenameofeachcookie.Youwouldthink"${cookies.value}"returnsthevalueforeachcookie;however,thissyntaxreturnstheCookieobjectitself.Theweirdsyntax"${cookies.value.value}"returnsthevalueofthecookie.Figure23-8showshowtheJSPdisplaysthisinformation.
Figure23-8.DisplayingacookieobjectandvaluewiththeJSTL
SeeAlso
Chapter10onreadingandsettingcookies;theJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;theSunMicrosystemsJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.4andRecipe23.5onusingtheXMLtags;Recipe23.6onusingtheformattingtags;Recipe23.7andRecipe23.8onusingtheSQLJSTLtags;Recipe23.9-Recipe23.12onusingtheELtoaccessscopedvariables,requestparameters,andrequestheaders;Recipe23.14onusingtheELtoaccessJavaBeanproperties.
Recipe23.14UsingtheELtoAccessJavaBeanProperties
Problem
YouwanttousetheELtoaccessthepropertiesofaJavaBeaninaJSP.
Solution
Usethejsp:useBeanstandardactiontocreateoraccessaninstanceofthebean,thenusetheELtoaccessthebeanproperties.
Discussion
Youcanusethec:outJSTLcoretagandtheELtodisplaythevaluesofJavaBeanpropertiesinaJSP.Example23-15showstheskeletonofaJavaBeanthatisdesignedtohandleemail.IusedthisbeaninChapter20,whichcontainsdetailsaboutallofitsemail-sendingand-accessingmethods.
Example23-15.AJavaBeanthataJSPwillinstantiateandaccess
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.util.Properties;
importjavax.mail.*;
importjavax.mail.internet.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassEmailBean{
//defaults
privatefinalstaticStringDEFAULT_SERVER="smtp.comcast.net";
privatefinalstaticStringDEFAULT_TO=
privatefinalstaticStringDEFAULT_FROM=
privatefinalstaticStringDEFAULT_CONTENT="Unknowncontent";
privatefinalstaticStringDEFAULT_SUBJECT="Unknownsubject";
//JavaBeanproperties
privateStringsmtpHost;
privateStringto;
privateStringfrom;
privateStringcontent;
privateStringsubject;
//no-argsconstructorforthebean
publicEmailBean(){}
//configureanemailmessagewithrequestparamsandsendtheemail
publicvoidsendMessage(HttpServletRequestrequest,
PrintWriterout)throwsIOException{
//SEERECIPE20.3AND20.6FORMOREDETAILSONTHISEMAILBEAN
//METHOD
}//sendMessage
//getemailmessagesusingaPOPaccount
privatevoidhandleMessages(HttpServletRequestrequest,
PrintWriterout)throwsIOException,ServletException{
//SEERECIPE20.3AND20.6FORMOREDETAILSONTHISEMAILBEAN
//METHOD
}//handleMessages
//displayinfoaboutreceivedemailmessages
privatevoiddisplayMessage(Messagemsg,PrintWriterout)
throwsMessagingException,IOException{
//SEERECIPE20.3AND20.6FORMOREDETAILSONTHISEMAILBEAN
}//displayMessage
//getteroraccessormethods
publicStringgetSmtpHost(){
return(smtpHost==null||smtpHost.equals(""))?
EmailBean.DEFAULT_SERVER:smtpHost;
}//getSmtpHost
publicStringgetTo(){
returnto;
}//getTo
publicStringgetFrom(){
returnfrom;
}//getFrom
publicStringgetContent(){
returncontent;
}//getContent
publicStringgetSubject(){
returnsubject;
}//getSubject
//setterormutatormethods
publicvoidsetSmtpHost(Stringhost){
if(check(host)){
this.smtpHost=host;
}else{
this.smtpHost=EmailBean.DEFAULT_SERVER;
}
}//setSmtpHost
publicvoidsetTo(Stringto){
if(check(to)){
this.to=to;
}else{
this.to=EmailBean.DEFAULT_TO;
}
}//setTo
publicvoidsetFrom(Stringfrom){
if(check(from)){
this.from=from;
}else{
this.from=EmailBean.DEFAULT_FROM;
}
}//setFrom
publicvoidsetContent(Stringcontent){
if(check(content)){
this.content=content;
}else{
this.content=EmailBean.DEFAULT_CONTENT;
}
}//setContent
publicvoidsetSubject(Stringsubject){
if(check(subject)){
this.subject=subject;
}else{
this.subject=EmailBean.DEFAULT_SUBJECT;
}
}//setSubject
privatebooleancheck(Stringvalue){
if(value==null||value.equals(""))
returnfalse;
returntrue;
}
}
Example23-16showstheJSPthatcreatesaninstanceofthisbeanusingthejsp:useBeanstandardaction.Theidattributeofjsp:useBeanspecifies"emailer"asthebeanname.Thisisthenamethecodeusestoaccessthebeaninstance'spropertyvaluesusingtheEL.
Example23-16.CreatingaJavaBeanandusingtheJSTLtodisplayitspropertyvalues
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="emailer"class="com.jspservletcookbook.EmailBean"/>
<jsp:setPropertyname="emailer"property="*"/>
<html>
<head><title>Beanpropertydisplay</title></head>
<body>
<h2>HerearetheEmailBeanproperties</h2>
<strong>SMTPhost:</strong><c:outvalue="${emailer.smtpHost}"/>
<strong>Emailrecipient:</strong><c:outvalue="${emailer.to}"/>
<strong>Emailsender:</strong><c:outvalue="${emailer.from}"/>
<strong>Emailsubject:</strong><c:outvalue="${emailer.subject}"/>
<strong>Emailcontent:</strong><c:outvalue="${emailer.content}"/>
</body>
</html>
Whenthecodeusesanexpressionsuchas"${emailer.smtpHost},"itcallsthegetSmtpHost()methodoftheEmailBean(theSMTPserverfromwhichyoureceiveemail,suchas"smtp.comcast.net").ThevariableemailerreferstotheinstanceoftheEmailBean.
Example23-16setalloftheEmailBean'ssettablepropertiesfromrequestparametersofthesamename.Thisisthepurposeofthecode:
<jsp:setPropertyname=
"emailer"property="*"/>
Providingthec:outvalueattributewiththisexpressionoutputsthevalueofthebean'sproperty.Figure23-9showstheJSPofExample23-
16inawebbrowser.
Figure23-9.DisplayingaJavaBean'spropertiesusingJSTLc:outtags
SeeAlso
Chapter20onusingJavaBeanstohandleemail;theJakartaProject'sTaglibssite:http://jakarta.apache.org/taglibs/index.html;theSunMicrosystemsJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.3onusingthecoretags;Recipe23.4andRecipe23.5onusingtheXMLtags;Recipe23.6onusingtheformattingtags;Recipe23.7andRecipe23.8onusingtheSQLJSTLtags;Recipe23.9-Recipe23.13onusingtheELtoaccessscopedvariables,requestparameters,requestheaders,andcookies.
Recipe23.15UsingJSTLFunctions
Problem
Youwanttousethebuilt-infunctionsincludedwithJSTL1.1.
Solution
Usethepropertaglibdirective(withtheurivalueof"http://java.sun.com/jsp/jstl/functions")andprefix(e.g.,thefn:infn:contains)inyourJSP.
Discussion
TheJSTL1.1anditsELincludesaniftynewfunctionslibrary.ThesetagsallowJSPdeveloperstocallbuilt-infunctionstohandleandreturnvaluesfromStrings,arrays,Maps,andCollections.Thenatureofthesefunctionswillbefamiliartoanyonewhohasworkedwithjava.lang.Stringanditsnumerousmethods(seeTable23-4).FunctionsrepresentanevolutionofJSTLfrominvolvingacollectionofcustomtagstogivingyoutheabilitytomakefunctioncallsembeddedinsidetemplatetext.
HereisthesetupthatyouneedtouseJSTLfunctionsinyourJSPs:
1. AJSP2.0JSPcontainer
AnimplementationofJSTL1.1(IusetheJavaWebServicesDeveloperPack1.2inthisrecipe)
Aconversionofyourweb.xmlfiletotheservletAPIVersion2.4(seelateroninthisrecipe)
Example23-17showsthenewtagliburiandprefixvaluestousewiththefunctionslibrary.ThisJSPusestheString"IamatestString"asinputtofouroftheavailablefunctions:fn:length(),fn:contains(),fn:toUpperCase(),andfn:split().
Example23-17.AJSPthatusesJSTL1.1functions
<%@tagliburi="http://java.sun.com/jsp/jstl/functions"prefix="fn"%>
<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>
<html>
<head><title>UsingtheJSTLfunctions</title></head>
<body>
<h2>UsingvariousJSTL1.1functions</h2>
<c:setvar="tempStr"value="IamatestString"/>
ThelengthofthetestString:${fn:length(tempStr)}<br/>
DoesthetestStringcontain"test"?${fn:contains(tempStr,"test")}<br/>
PuttingtheStringintouppercaseusingfn:toUpperCase():${fn:toUpperCase(tempStr)}<br
/>
SplittingtheStringintoaStringarrayusingfn:split(),andreturningthearray
length:${fn:length(fn:split(tempStr,""))}
</body>
</html>
JSTL1.1functioncallscanbeintermingledwithtemplatetext,asin
Example23-17.SurroundthefunctioncallswiththeELdelimiters("${...}"),andmakesuretousethefn:prefix,asin${fn:toUpperCase(tempStr)}.
Example23-18showshowyoucanchangeweb.xmltotheservletAPI2.4version,sothattheJSP2.0containerinterpretstheELfunctionsinyourcode.
ThemajordifferencebetweenJSTL1.0and1.1isthattheJSP2.0specificationhastakenovertheELresponsibility.Therefore,theJSP2.0container,nottheJSTLlibraries,nowevaluatestheELsyntax.
IfyoustickwiththeservletAPI2.3deploymentdescriptor,thentheJSP2.0containerwillnotevaluatetheELexpressionsandfunctioncalls.Usingtheoldservlet2.3deploymentdescriptor"turnsoff"ELevaluationbytheJSPcontainer;consequently,youcannotusethefunctionslibraryorincludeELsyntaxintemplatetext.ThisautomaticdisablingofELexpressionsbytheJSPcontainerisdesignedasawayofeasingthemigrationofexistingJSPpagestoJSP2.0.Inshort,aJSPthatincludestheJSTL1.0usagesandisassociatedwithaservlet2.3deploymentdescriptorworksthesameunderaJSP2.0container.
However,youmaywanttousethenewfunctions!Therefore,Example23-18showshowtomigratetotheservlet2.4versionofweb.xml.
Example23-18.Changeweb.xmltoservletAPI2.4touseJSTL1.1features
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<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_2_4.xsd"
version="2.4"
>
<!--RESTOFDEPLOYMENTDESCRIPTORELEMENTS-->
</web-app>
Example23-18alterstheweb-appelementtoincludetherequiredattributesoftheservlet2.4deploymentdescriptor(SeeChapter1).Therestofweb.xmlcanremainasitappearedusingtheservlet2.3DTD.
Table23-4describesthepurposeofeachfunctionthattheJSTL1.1includesinitsfunctionlibrary.
Table23-4.JSTL1.1functions
Functionname Arguments Returntype Purpose
fn:contains String,String boolean
FindsoutwhetheraString(firstargument)containsacertainsubstring(secondargument)
fn:containsIgnoreCase String,String boolean
FindsoutwhetheraStringcontainsasubstring(secondargument)inacase-insensitivemanner
fn:endsWith String,String boolean
FindsoutwhetheraString(firstargument)endswithanotherString(secondargument)
fn:escapeXML String String
EscapescharactersthatcouldbeinterpretedasXMLmarkup,suchas">"
fn:indexOf String,String int
ReturnstheindexorpositionofoneString(secondargument)insideanother(firstargument)
JoinsallString[]arrayelements
fn:join String[],String String
intoaString,usingthespecifiedseparator(secondargument)asthecharacterbetweeneacharrayelement.
fn:length
Map,array,
Collection,
Iterator,
Enumeration,or
String
intFindsoutthelengthofthearray,collection,orString.
fn:replaceString,String,
StringString
ReplacesallinstancesofaString(secondargument)inaninputString(firstargument)withanotherString(third)
fn:split String,String String[]
SplitsaStringintoanarray,usingthespecifieddelimiter(s)(secondargument)
fn:startsWith String,String booleanFindsoutwhetheraString(firstargument)startswithanotherString.
fn:substring String,int,int String
ReturnsasubstringfromtheinputString(firstargument),fromtheindexsecondargument(inclusive)totheindexthirdargument(exclusive)
fn:substringAfter String,String String
ReturnsthepartoftheStringafterthespecifiedsubstring(secondargument)
fn:substringBefore String,String String
ReturnsthepartoftheStringbeforethespecifiedsubstring(secondargument),beginingwiththefirstcharacterofthefirstStringargument.
fn:toLowerCase String StringReturnsthespecifiedStringinalllowercase.
fn:toUpperCase String StringReturnsthespecifiedStringinalluppercase.
fn:trim String String RemoveswhitespacefromeachendofthespecifiedString.
Figure23-10showsthewebbrowseroutputofaJSPthatusesvariousmembersoftheJSTL1.1functionslibrary.
Figure23-10.AJSPdisplaystheresultsofusingsomeJSTL1.1functions
SeeAlso
SunMicrosystem'sJSTLinformationpage:http://java.sun.com/products/jsp/jstl/;Recipe23.2onusingthecoretags;Recipe23.3andRecipe23.4onusingXML-relatedtags;Recipe23.5onformattingdatesandnumbers;Recipe23.6andRecipe23.7ontheJSTL'sSQLfeatures;Recipe23.8onaccessingscopedvariables;Recipe23.9onusingtheELwithrequestparameters;Recipe23.10andRecipe23.11onusingtheELwithrequestheaders;Recipe23.12onfindingoutinformationaboutcookies;Recipe23.13onusingtheELtoaccessJavaBeanproperties.
Chapter24.InternationalizationIntroduction
Recipe24.1.DetectingtheClientLocaleinaServlet
Recipe24.2.DetectingtheClient'sLocalesinaJSP
Recipe24.3.CreatingaResourceBundleasaPropertiesFile
Recipe24.4.CreatingaResourceBundleasaJavaClass
Recipe24.5.UsingtheResourceBundleinaServlet
Recipe24.6.UsingtheResourceBundleinaJSP
Recipe24.7.FormattingDatesinaServlet
Recipe24.8.FormattingDatesinaJSP
Recipe24.9.FormattingCurrenciesinaServlet
Recipe24.10.FormattingCurrenciesinaJSP
Recipe24.11.FormattingPercentagesinaServlet
Recipe24.12.FormattingPercentagesinaJSP
Recipe24.13.SettingtheLocalizationContextintheDeploymentDescriptor
Introduction
Theaudienceforalmostallwebsitesisglobal.Manysiteshaveatleastasubsetofcontentthatmustbeadaptedtothelanguageandnationalityoftheirvisitors,sothatthevisitor'sbrowserformatsnumbersanddatesproperlyandtranslatestextintotheproperlanguage.Anobviousexampleisaproductdocumentationorhelpwebsite.WhatifmostofyourcustomersorviewersforthisproductspeakalanguageotherthanEnglish?Javaprovidestoolsthatallowwebdeveloperstointernationalizetheirsites.
BeforeIshowthesetools,let'sfirstexplainafewtermsthatalwaysappearindiscussionsofwebsitetranslation.
1. Internationalization,ori18ninitsabbreviatedversion,meansenablingawebsiteorotherJavaprogramtoprovidedifferentversionsofcontenttranslatedintothevisitor'slanguageornationality.Thistermbasicallymeansmakingyoursiteglobal.
Localization,orl10n,meansaddingresourcestoawebsitetoadaptittoaparticulargeographicalorculturalregion.Anexampleofl10nisaddingKoreanlanguagetranslationstoawebsite.Thewebdeveloperswhohavethisresponsibilityareoftenreferredtoaslocalizers.
Alocaleisaparticularculturalorgeographicalregion.Itisusuallyreferredtoasalanguagesymbolfollowedbyacountrysymbol(separatedbyanunderscorecharacter),asin"en_US"fortheEnglishlocale,"de_DE"forGermanspeakersinGermany,or"de_CH"forSwiss-Germanspeakers,or"fr_CH"forpeopleinSwitzerlandwhospeakFrench.Alocalecanalsorepresentjustthelanguage,asin"ja"forJapaneseor"it"forItalian.Finally,localescanhaveathirdsegmentor"variant"thatreflectsacertainbrowser-typeorvendor,suchas"MAC"forMacintosh.AnexampleofalocaleforEnglishwithaWindowsvariantis"en_US_WIN."
ThelanguageelementisrepresentedbyanInternationalStandardsOrganization(ISO)languagecode(http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt);thecountryisencodedunderISO-3166(http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html).
SohowdoyouinternationalizeorlocalizeaJavawebsite?Thisisabigsubjectandthetopicofseveralbooks.Thefollowingrecipesprovidethebasicsofhowtocreatepropertiesfiles(calledResourceBundles).Thesefiles(theycanalsobeimplementedasJavaclasses)providelanguagetranslationsforphrasesthatyourwebpagesuse.Aservletcanthenaccesstheseresourcesandprovidedifferenttextversionsaccordingtotherequester'slocale.
TherecipesinthischapteralsocoverhowtoadaptJSPpagestovisitorswhospeakdifferentlanguagesbyusingtheJSTLtags.IbeginbydescribinghowtodetectthelocaleofarequestusingaservletorJSP.
Recipe24.1DetectingtheClientLocaleinaServlet
Problem
Youwanttodetecttheclientlocaleinaservlet.
Solution
UsetheServletRequest.getLocale()method.
Discussion
ThelocaleisrepresentedbyaclassinJava:java.util.Locale.TheServletRequestobjectcanaccesstheclient's"preferred"localewithitsgetLocale()method,whichreturnsaLocaleobject.
Thepreferredlocaleistheuser'stoppreference.Forexample,ausermayconfiguretheirbrowserwithaSpanishlanguagelocale("es_ES")asthepreferredone.
JavacodecanaccessthelistoflocalesthatauserconfiguresabrowserwithbycallingServletRequest'sgetLocales()method,whichreturnsanEnumerationobject.Thisobjectcontainsthepreferredandless-preferredlocales.
Tosetthelanguagepreference(s)inNetscape7.1,goto"Edit PreferencesNetscape Languages."IntheMacintoshSafaribrowser,openSystem
Preferencesanddragyourlanguagepreference(s)tothetopofthelist(thenrestartSafari).InInternetExplorer5.5,goto"Tools InternetOptionsLanguages."
Example24-1accessestheclient'spreferredlocalebycallingrequest.getLocale().TheservletthendisplaysinformationaboutthelocalebycallingsomeLocalemethods.Example24-1alsodisplaysinfomationabouttheless-preferredlocalesbyusingthemethodrequest.getLocales().
Example24-1.AccessingtheLocaleobjectinaservlet
packagecom.jspservletcookbook;
importjava.util.Enumeration;
importjava.util.Locale;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassLocaleDisplayextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//Gettheclient'sLocales
Enumerationenum=request.getLocales();
//GetthepreferredLocale
Localepreferred=request.getLocale();
StringprefDisplay="";
if(preferred!=null)
prefDisplay=preferred.getDisplayName();
//Displaythepreferredandanyotherlocales
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>LocaleDisplay</title></head><body>");
out.println("<h2>HereisyourLocaleinfo...</h2>");
out.println("<b>PreferredLocale:</b>");
out.println(prefDisplay);
out.println("<br/>");
out.println("Localecountry:");
if(preferred!=null)
out.println(preferred.getDisplayCountry());
out.println("<br/>");
out.println("Localelanguage:");
if(preferred!=null)
out.println(preferred.getDisplayLanguage());
out.println("<br/><br/>");
out.println("<h3>LowerpriorityLocales...</h3>");
Localeloc=null;
while(enum.hasMoreElements()){
loc=(Locale)enum.nextElement();
if(!(loc.getDisplayName().equals(prefDisplay))){
out.println("Locale:");
out.println(loc.getDisplayName());
out.println("<br/>");
out.println("Localecountry:");
out.println(loc.getDisplayCountry());
out.println("<br/>");
out.println("Localelanguage:");
out.println(loc.getDisplayLanguage());
out.println("<br/><br/>");
}//if
}//while
out.println("</body></html>");
}//doGet
}
Figure24-1showsthewebbrowseroutputwhenavisitorwithapreferredlocaleof"en_US"requeststheservlet.
Figure24-1.Theservletdisplaysthepreferredandless-preferredlocales
Thisuserhasconfiguredtheirbrowserwithseveralotherlocales.Asyoucansee,themethodlocale.getDisplayName()isdesignedtoreturnamorereadablename(comparedwith"de_CH")forthelocale.
Thecom.oreilly.servletlibraryincludestheLocaleNegotiatorclass,
whichusestheclientrequesttofigureoutthebestcharset,locale,andresourcebundletousewiththeresponse.SeeRecipe8.4fortipsonusingthecom.oreilly.servletlibrary.Idon'tcoverLocaleNegotiatorinparticularhere,buttheJavadocexplainsthisclass.Seehttp://www.servlets.com/cos/javadoc/com/oreilly/servlet/LocaleNegotiator.html.
SeeAlso
TheJavadocdescribingtheLocaleclass:http://java.sun.com/j2se/1.4.1/docs/api/java/util/Locale.html;Recipe24.2ondetectingthelocaleusingaJSP.
Recipe24.2DetectingtheClient'sLocalesinaJSP
Problem
Youwanttofindoutwhattherequest'spreferredlocaleandless-preferredlocalesareanddisplaythisinformationinaJSP.
Solution
Grabthepreferredlocalewiththeexpression"${pageContext.request.locale}."Getaccesstoallofthelocaleswiththeexpression"${pageContext.request.locales}."
Discussion
TheJSTLtagsmakeiteasytoadaptaJSPforvisitorswhospeakdifferentlanguages.Example24-2usestheELtocreateavariablenamedclientLocalethatrepresentstherequest'spreferredlocale.ThentheJSPdisplaysthelocale'sname,language,andcountry.Example24-2alsodisplaysanyinformationabouttheclient'sless-preferredlocales.
Example24-2.Accessingtherequest'slocaleinaJSP
<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>
<html>
<head><title>LocaleDisplay</title></head>
<body>
<h2>Hereisyourpreferredlocaleinfo...</h2>
<c:setvar="clientLocale"value="${pageContext.request.locale}"/>
<c:setvar="clientLocales"value="${pageContext.request.locales}"/>
Preferredlocale:${clientLocale.displayName}
<br/>
Preferredlocalecountry:${clientLocale.displayCountry}
<br/>
Preferredlocalelanguage:${clientLocale.displayLanguage}
<h3>Lowerprioritylocales...</h3>
<c:forEachvar="loc"items="${clientLocales}"begin="1">
Locale:${loc.displayName}
<br/>
Localecountry:${loc.displayCountry}
<br/>
Localelanguage:${loc.displayLanguage}
<br/><br/>
</c:forEach>
</body>
</html>
Theexpression"${pageContext.request.locale}"getstherequestobjectfromthepageContextimplicitobject,thenaccessestheLocaleobject,representingtheclient'spreferredlocale,fromtherequest.Fairlyefficient,huh?Thenanexpressionsuchas"${clientLocale.displayName}"representstheequivalentofcallingtheLocaleobject'sgetDisplayName()method.
TheELphrase"${pageContext.request.locales}"representstheequivalentofcallingtheServletRequestobject'sgetLocales()method,whichreturnsajava.util.Enumerationtype.TheEnumerationcontainsalloftheclient'sconfiguredlocales,beginingwiththeirpreferredlocale.
Example24-2usesanimplmentationofJSTL1.1andJSP2.0.MakesuretoincludethepropertaglibdirectiveatthetopoftheJSPfile,sothattheJSPcanusetheELandcoretags.Ifallthisterminologyisnewandstrangetoyou,readChapter23ontheJSTL.
Example24-2iteratesthrougheachofthelocalesusingthec:forEachtag,asin:
<c:forEachvar="loc"items="${clientLocales}"begin="1">
Thebegin="1"attributebeginsthec:forEachiterationwiththesecondlocaleobject,sincethefirstlocaleistheclient'spreferredone,andtheJSPhasalreadydisplayedinformationonthatone.Thebeginattributeuses"0"astheindexforthefirstitemintheEnumeration.
Figure24-2showstheJSP'swebbrowseroutput.Thisoutputresultsfromavisitorwhosebrowserspecifiesthelocale"es_ES"aspreferred.
Figure24-2.Abrowserrequestsalocale-sensitiveJSP
SeeAlso
Chapter23ontheJSTL;theJavadocdescribingtheLocaleclass:http://java.sun.com/j2se/1.4.1/docs/api/java/util/Locale.html.
Recipe24.3CreatingaResourceBundleasaPropertiesFile
Problem
Youwanttostoreyouri18nresourcesinyourwebapplication.
Solution
Createatextfilewithname/valuepairsrepresentingyouri18nresources.NamethefilewithyourglobalresourcenameandstoreitbeneathWEB-INF.
Discussion
Addingi18n-relatedresourcestoyourwebapplicationinvolvescreatingpropertiesfilesorResourceBundleclasses(Recipe24.4).AResourceBundlethattakestheformofapropertiesfileissimplyalistofkeysandvalues,producedinanytexteditor.Thekeysrepresentsthewordsthatyouwanttobetranslated,andthevaluesarethetranslations.Thesefilesaretheresourcesthatthewebapplicationusestodynamicallytranslatetextintotheappropriatelanguage.
Imaginethatyouarecreatingsomeresourceswithaglobalname,orbasename,of"WelcomeBundle."Example24-3showsthesubclassofthisresourceforthevisitorsfromthelocale"es_ES,"orpeoplefromSpainwhospeakSpanish.
Forexample,thekey"Welcome"isassociatedwithitsSpanishequivalent"Holayrecepción."Recipe24.5showshowaservletwoulduseaResourceBundlelikethistodynamicallytranslate"Welcome"to
thevisitor'slanguage.
Example24-3.ThecontentsofaResourceBundlefilenamedWelcomeBundle_es_ES.properties
#Spanishlanguageresources
Welcome=Holayrecepción
Thesearejustkeysandvaluesseparatedbynewlinecharacters.Commentsaredelineatedbyahash(#)character.
Thistextfilehastobestoredinaplacewhereotherwebcomponentscanfindit,similartoinstallingaJavaclassinyourwebapplication.Thisisthepathtothepropertiesfile,whichhasafullyqualifiednameofi18n.WelcomeBundle_es_ES.properties.The.propertiesextensionisanessentialdetail!
WEB-INF/i18n/WelcomeBundle_es_ES.properties
Centralizingthei18nresourcesintheirownWEB-INFsubdirectoryinawebapplicationisasensiblewaytoorganizethisinformationandavoidclutter.
SeeAlso
Recipe24.4oncreatingResourceBundleasaJavaclass;thePropertyResourceBundleJavadoc:http://java.sun.com/j2se/1.4.1/docs/api/java/util/PropertyResourceBundle.html
Recipe24.4CreatingaResourceBundleasaJavaClass
Problem
YouwanttocreateaResourceBundleasaJavaclass.
Solution
Createaclassthatextendsjava.util.ListResourceBundle.
Discussion
Ifyourapplicationrequiresmorefunctionalitythanastaticpropertiesfilecanprovide(Recipe24.3),youcancreateyourResourceBundlesasJavaclasses:java.util.ListResourceBundletypes.Forinstance,aparticularresourcemightneedtoselectitstranslationinformationfromadatabase.
Example24-4includesthesameinformationasthepropertiesfileinthepriorrecipe.However,itskey/valuepairsarestoredintheformofatwo-dimensionalObjectarray.Thisclassisstoredinthesameplaceasthe.propertiesfilesinWEB-INF/i18n.
Example24-4.StoringlanguageinformationinaListResourceBundle
packagecom.jspservletcookbook;
importjava.util.ListResourceBundle;
publicclassWelcomeBundle_es_ESextendsListResourceBundle{
staticfinalObject[][]contents={
{"Welcome","Holayrecepción"}
};
publicObject[][]getContents(){
returncontents;
}
}
Thiscodesnippetfromaservletshowshowyoucouldusethisclass.
Example24-5.CallingaListResourceBundlemethodfromaResourceBundlecreatedasaJavaclass
<!--insideservletgoGet()ordoPost()method,forinstance-->
ResourceBundlebundle=ResourceBundle.getBundle(
"i18n.WelcomeBundle_es_ES");
//CallinheritedListResourceBundlegetKeys()method
java.util.Enumerationenum=bundle.getKeys();
while(enum.hasMoreElements()){
//Printsoutkey:"Welcome"
out.println((String)enum.nextElement());
out.println("<br/><br/>");
}//while
TheResourceBundle.getBundle()staticmethodtriestofindaJavaclasswiththefullyqualifiedname"i18n.WelcomeBundle_es_ES"(inthisexample).Failingthat,itlooksforapropertiesfileofthesamename(minusthe.propertiesextension):i18n.WelcomeBundle_es_ES.properties.
SeeAlso
TheJavadocforListResourceBundle:http://java.sun.com/j2se/1.4.1/docs/api/java/util/ListResourceBundle.html;Recipe24.3oncreatingaResourceBundleasapropertiesfile.
Recipe24.5UsingtheResourceBundleinaServlet
Problem
Youwantaservlettodynamicallydisplaya"Welcome"messagetovisitorsdependingontheirlocale.
Solution
UsetheservlettoaccessthetranslatedtextdynamicallyfromaResourceBundle.
Discussion
OnceyouhaveaddedResourceBundlestothewebapplication,thenservletscanusethemtodynamicallydisplaytextbasedontheuser'slocale.
Remember,thewebapplicationstoresResourceBundlesas.propertiesfiles(text)orJavaclasses.
Example24-6usesaResourceBundlewithabasenameof"WelcomeBundle."ItisstoredinWEB-INF/i18n,soitsfullyqualifiednameisi18n.WelcomeBundle.
Example24-6.Aservletusesatodynamicallydisplaytranslatedtext
packagecom.jspservletcookbook;
importjava.util.Locale;
importjava.util.ResourceBundle;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassWelcomeServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//Gettheclient'sLocale
Localelocale=request.getLocale();
ResourceBundlebundle=ResourceBundle.getBundle(
"i18n.WelcomeBundle",locale);
Stringwelcome=bundle.getString("Welcome");
//Displaythelocale
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head><title>"+welcome+"</title></head><body>");
out.println("<h2>"+welcome+"</h2>");
out.println("Locale:");
out.println(locale.getLanguage()+"_"+locale.getCountry());
out.println("</body></html>");
}//enddoGet
//doPostmethod...
}//WelcomeServlet
HereishowtheapplicationusesthisresourceinresponsetoavisitorfromaSpanishlocale("es_ES"):
1. Theservletaccessesthelocaleasajava.util.Localeobject.
ItpassesthelocaleintotheResourceBundle.getBundle()method,whichusesthelocaletosearchforaResourceBundlenamedi18n.WelcomeBundle_es_ES.Themethodformsthissearchtermbyattachingthecurrentrequest'slocalenametotheendoftheResourceBundlebasename.Inthiscase,thebundleisstoredasaJavaclass(Recipe24.4).
Thebundlethendisplaysthemessagebyaccessingthe"Welcome"key,whichisspecifiedbytheResourceBundle(Example24-4orExample24-5).
Sometimesthebrowsersendsthelocaleinformationasalanguagecodeonly,asin"es"forSpanish(insteadof"es_ES"withlanguagecodeandcountrycode).IftheapplicationhasonlyinstalledaresourcenamedWelcomeBundle_es_ES,butnotWelcomeBundle_es,thenthegetBundle()methoddefaultstoaresourcenamedWelcomeBundle(whichmightnotbetheoptimaloutcome),andthereforemaynotdisplaythetranslatedtext.MakesuretoincludeaWelcomeBundle_esresourcetocoverthesecases.
Figure24-3showstheservlet'soutputinresponsetoarequestfromaSpanishlocale.
Figure24-3.ASpanishclientrequeststheLocaleServlet
Figure24-4showstheservlet'sresponsewhenitdealswithalocaleforwhichtheapplicationhasnotprovidedaresource.Inthiscase,thebrowserissetfortheJapaneselanguage,buttheapplicationhasnotyetprovidedaresourceforthislocale.
Figure24-4.AbrowsersetforJapanesevisitsreceivesthedefaultmessage
Thetextthatthebrowserdisplaysderivesfromthedefaultpropertiesfile:WelcomeBundle.properties(noticetheabsenceofanylocale-relatedsuffixinthefilename).
SeeAlso
Recipe24.6onusingtheResourceBundleinaJSP;TheJavadocforResourceBundle:http://java.sun.com/j2se/1.4.1/docs/api/java/util/ResourceBundle.html.
Recipe24.6UsingtheResourceBundleinaJSP
Problem
YouwanttodynamicallydisplaytextintheJSPaccordingtothelocaleoftherequest.
Solution
UsetheJSTLtagsfromtheformattinglibrary.
Discussion
TheJSTL'sformattingtagsmakeiteasytodynamicallydisplaytextbasedonthebrowser'slanguagesetting.Example24-7makesavailabletheformattingandcoreJSTLtagswiththetaglibdirective.Thenitusesthefmt:setBundletagtospecifythei18nresourcesthatwillbeusedbythepage(thelocalizationcontext).
Example24-7.Usingtheformattingtagstodisplayalocale-sensitivemessageinaJSP
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%@tagliburi="http://java.sun.com/jstl/fmt"prefix="fmt"%>
<fmt:setBundlebasename="i18n.WelcomeBundle"/>
<html>
<head><title><fmt:messagekey="Welcome"/></title></head>
<body>
<h2><fmt:messagekey="Welcome"/></h2>
Locale:<c:outvalue=
"${pageContext.request.locale.language}"/>_<c:outvalue=
"${pageContext.request.locale.country}"/>
</body>
</html>
Justliketheservletcodeinthepriorrecipe,thetagdynamicallyusestheWelcomeBundleresourcebasedontherequest'slocale.Inotherwords,ifthebrowser'slocaleis"es_ES,"aSpanishlocale,thenthefmt:messagetagsusesthekeysandvaluesfromtheWelcomeBundle_es_ESpropertiesfileorJavaclass(howeveritisimplemented).
Ifyousetthelocalizationcontextasacontext-paramelementinthedeploymentdescriptor,theJSPdoesnothavetousethefmt:setBundletag.SeeRecipe24.13.
IntheJSP,thecode:
<fmt:messagekey="Welcome"/>
isreplacedbythevalueofthe"Welcome"keyinthechosenResourceBundlefile("Holayrecepción").TheresultofrequestingthisJSPlooksjustlikeFigure24-3inRecipe24.5.
SeeAlso
Recipe24.5onusingtheResourceBundleinaservlet;Chapter23ontheJSTL;theJavadocforResourceBundle:http://java.sun.com/j2se/1.4.1/docs/api/java/util/ResourceBundle.html.
Recipe24.7FormattingDatesinaServlet
Problem
Youwanttoformatadatefordisplayinaservletbasedontherequest'slocale.
Solution
Usethejava.text.DateFormatclass.
Discussion
Differentcountrieshavetheirownwaysofdisplayingthedateandtime.TheDateFormatclass,likemanyoftheclassesinthejava.textpackage,is"localesensitive."Yourcodedisplaysthedatedependingonthebrowser'slanguagesetting.AllyouhavetodoispasstheLocaleobjecttothestaticDateFormat.getDateTimeInstance()method,asintheservletofExample24-8.
Example24-8.DisplayingadateStringinalocale-sensitivemanner
packagecom.jspservletcookbook;
importjava.text.DateFormat;
importjava.util.Date;
importjava.util.Locale;
importjava.util.ResourceBundle;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassDateLocaleServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//Gettheclient'sLocale
Localelocale=request.getLocale();
ResourceBundlebundle=ResourceBundle.getBundle(
"i18n.WelcomeBundle",locale);
Stringwelcome=bundle.getString("Welcome");
Stringdate=DateFormat.getDateTimeInstance(DateFormat.FULL,
DateFormat.SHORT,locale).format(newDate());
//Displaythelocale
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head><title>"+welcome+"</title></head><body>");
out.println("<h2>"+bundle.getString("Hello")+""+
bundle.getString("and")+""+
welcome+"</h2>");
out.println(date+"<br/><br/>");
out.println("Locale:");
out.println(locale.getLanguage()+"_"+locale.getCountry());
out.println("</body></html>");
}//doGet
//implementdoPostandcalldoGet(request,response);
}
TheDateFormat.getDateTimeInstance()methodincludesparametersintheformofconstants(e.g.,DateFormat.FULL)thatallowyourcodetocustomizethedateformat.Example24-8displaysthedateinawaythatincludesthenameofthedayoftheweekandashortformforthetime.Youcanexperimentwiththeseconstantsinordertodeterminehowbrowsersdisplaytheservlet'soutput.Figure24-5showshowthedateisdisplayedinresponsetoaGerman-languagelocaleof"de_DE."
Figure24-5.Displayingthedateinaservletaccordingtotherequest'slocale
SeeAlso
TheJavadocfortheDateFormatclass:
http://java.sun.com/j2se/1.4.1/docs/api/java/text/DateFormat.html;Recipe24.8onformattingdatesinaJSP.
Recipe24.8FormattingDatesinaJSP
Problem
YouwanttodisplayadateinaJSPthatiscustomizedfortheuser'slocale.
Solution
Usethefmt:formatDateJSTLtag.
Discussion
TheJSTLincludesthe"formatting"library,whichallowsJSPcodetodisplaydatesinalocale-sensitivemanner.Example24-9usesthefmt:formatDatetag.Thecodeusesthestandardactionjsp:useBeantocreateajava.util.Dateobjectrepresentingthecurrentdateandtime.Thecodepassesthedateobjecttofmt:formatDate'svalueattribute.WhenauserrequeststheJSP,thefmt:formatDatetagisreplacedbytextdisplayingtheformatteddate.
Example24-9.Formattingadateusingfmt:formatDate
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%@tagliburi="http://java.sun.com/jstl/fmt"prefix="fmt"%>
<jsp:useBeanid="date"class="java.util.Date"/>
<html>
<head><title><fmt:messagekey="Welcome"/></title></head>
<body>
<h2><fmt:messagekey="Hello"/><fmt:messagekey="and"/>
<fmt:messagekey="Welcome"/></h2>
<fmt:formatDatevalue="${date}"type="both"dateStyle=
"full"timeStyle="short"/><br/>
Locale:<c:outvalue=
"${pageContext.request.locale.language}"/>_<c:outvalue=
"${pageContext.request.locale.country}"/>
</body>
</html>
Thefmt:messagetagsheredependonaconfigurationparameter,orcontext-paramelement,inthedeploymentdescriptor.Thecontext-paramelementspecifiesthei18n-relatedresources.SeeRecipe24.13.
TheelementhasattributesnameddateStyleandtimeStylethatallowthecodetocustomizetheformatofthedateandtimeStrings.
SeetheJavadocfortheDateFormatclassformoredetails:http://java.sun.com/j2se/1.4.1/docs/api/java/text/DateFormat.html.
TheoutputoftheJSPinExample24-9looksjustlikeFigure24-5inthepriorrecipe.
SeeAlso
TheJavadocfortheDateFormatclass:http://java.sun.com/j2se/1.4.1/docs/api/java/text/DateFormat.html;Chapter23ontheJSTL;Recipe24.7onformattingdatesinaservlet.
Recipe24.9FormattingCurrenciesinaServlet
Problem
Youwanttoformatacurrencyvalueaccordingtotherequest'slocale.
Solution
Usethejava.text.NumberFormatclass.
Discussion
TheNumberFormatclasscanformatanumber,suchasalongordoubletype,asapercentage.ThisclasshasastaticgetCurrencyInstance()method.Thismethodcantakeajava.util.Localeobjectasaparameter,todisplaythecurrencyaccordingtotheuser'slanguagesetting.
Example24-10isaservletthatdemonstratesthelocale-sensitivedisplayofacurrency,byshowingboththecurrencyamountandthelocalelanguageandcountrycode.
Example24-10.Formattinganumberasapercentageinaservlet
packagecom.jspservletcookbook;
importjava.text.NumberFormat;
importjava.util.Locale;
importjava.util.ResourceBundle;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassCurrLocaleServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//Gettheclient'sLocale
Localelocale=request.getLocale();
ResourceBundlebundle=ResourceBundle.getBundle(
"i18n.WelcomeBundle",locale);
Stringwelcome=bundle.getString("Welcome");
NumberFormatnft=NumberFormat.getCurrencyInstance(locale);
StringformattedCurr=nft.format(1000000);
//Displaythelocale
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head><title>"+welcome+"</title></head><body>");
out.println("<h2>"+bundle.getString("Hello")+""+
bundle.getString("and")+""+
welcome+"</h2>");
out.println("Locale:");
out.println(locale.getLanguage()+"_"+locale.getCountry());
out.println("<br/><br/>");
out.println(formattedCurr);
out.println("</body></html>");
}//doGet
//implementdoPost()tocalldoGet()...
}
TheNumberFormatclass'format()methodreturnsaStringthatrepresentstheformattedcurrency.Figure24-6showstheservlet'soutputwhenrequestedbyabrowserwheretheuserhassetthelanguagesettingtothelocale"en_GB"(Englishlanguage,GreatBritain).
Figure24-6.ABritishvisitorseestheformattedcurrencydisplayofonemillionpounds
SeeAlso
TheJavadocfortheNumberFormatclass:
http://java.sun.com/j2se/1.4.1/docs/api/java/text/NumberFormat.html;Recipe24.10onformattingcurrenciesinaJSP.
Recipe24.10FormattingCurrenciesinaJSP
Problem
YouwanttoformatcurrencyvaluesinaJSP.
Solution
UsetheJSTLtagfmt:formatNumber.
Discussion
Thefmt:formatNumbertagisdesignedtodisplayacurrencyvaluebasedonthevisitor'slocale.Example24-11firstusesthetaglibdirectivetomaketheJSTL1.0formattinglibraryavailabletotheJSP.
Example24-11.formattinganumberusingtheJSTL1.0tags
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%--theformattinglibraryincludesfmt:formatNumber--%>
<%@tagliburi="http://java.sun.com/jstl/fmt"prefix="fmt"%>
<html>
<head><title><fmt:messagekey="Welcome"/></title></head>
<body>
<h2><fmt:messagekey="Hello"/><fmt:messagekey="and"/><fmt:messagekey="Welcome"/></
h2>
Locale:<c:outvalue="${pageContext.request.locale.language}"/>_<c:out
value="${pageContext.request.locale.country}"/>
<br/><br/>
<fmt:formatNumbervalue="1000000"type="currency"/>
</body>
</html>
Thefmt:formatNumbertagisquitestraightforward.Thevalueattributetakesthenumberyouwanttoformatasacurrency,andthevalueofthetypeattributemustbe"currency."ThetextrepresentingtheformattednumberthenreplacesthetagwhenabrowserdisplaystheJSP'soutput.TheJSPinExample24-11displaysthesamebrowserinformationasshowninFigure24-6ofthepriorrecipe.
SeeAlso
Chapter23ontheJSTL;theJavadocfortheNumberFormatclass:http://java.sun.com/j2se/1.4.1/docs/api/java/text/NumberFormat.html;Recipe24.9onformattingcurrenciesinaservlet.
Recipe24.11FormattingPercentagesinaServlet
Problem
Youwanttoformatnumbersaspercentagesanddisplaytheminaservlet.
Solution
Usethejava.txt.NumberFormatclassanditsstaticgetPercentInstance()method.
Discussion
Example24-12usestheNumberFormat.getPercentInstance()method,withtheuser'slocaleasanargument,togetaNumberFormattypefordisplayinganumberasapercentage.ThecodeinExample24-12callstheNumberFormat'sformat()method,withanumberasanargument.
Theformat()methoddisplaysthenumber51as"5100%";adoubletypeincludingthedecimalpoint,suchas0.51producestheintendedresult(51%).
Example24-12.UsingNumberFormattodisplayapercentageinaservlet
packagecom.jspservletcookbook;
importjava.text.NumberFormat;
importjava.util.Locale;
importjava.util.ResourceBundle;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassPerLocaleServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//Gettheclient'sLocale
Localelocale=request.getLocale();
ResourceBundlebundle=ResourceBundle.getBundle(
"i18n.WelcomeBundle",locale);
Stringwelcome=bundle.getString("Welcome");
NumberFormatnft=NumberFormat.getPercentInstance(locale);
Stringformatted=nft.format(0.51);
//Displaythelocale
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head><title>"+welcome+"</title></head><body>");
out.println("<h2>"+bundle.getString("Hello")+""+
bundle.getString("and")+""+
welcome+"</h2>");
out.println("Locale:");
out.println(locale.getLanguage()+"_"+locale.getCountry());
out.println("<br/><br/>");
out.println("NumberFormat.getPercentInstance():"+formatted);
out.println("</body></html>");
}//doGet
//implementdoPost()tocalldoGet()...
}
Figure24-7showstheservlet'soutputinabrowser.
Figure24-7.Thebrowserdisplaysapercentageforacertainlocale
SeeAlso
TheJavadocfortheNumberFormatclass:http://java.sun.com/j2se/1.4.1/docs/api/java/text/NumberFormat.html;
Recipe24.12onformattingpercentagesinaJSP.
Recipe24.12FormattingPercentagesinaJSP
Problem
YouwanttodisplayanumberasapercentageinaJSP.
Solution
Usethefmt:formatNumbertag.
Discussion
TheJSTL'sfmt:formatNumbertagcandisplayanumberthecodeprovidesinthetag'svalueattributeasapercentage.Thevalueofthetypeattributemustbe"percent"(not"percentage").Example24-13passestheString".51"tothevalueattribute.Thiscodedisplaysthetext"51%"inthebrowser.
Example24-13.Usingthefmt:formatNumbertaginaJSPtodisplayapercentage
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<%@tagliburi="http://java.sun.com/jstl/fmt"prefix="fmt"%>
<html>
<head><title><fmt:messagekey="Welcome"/></title></head>
<body>
<h2><fmt:messagekey="Hello"/><fmt:messagekey="and"/><fmt:messagekey="Welcome"/></
h2>
Locale:<c:outvalue="${pageContext.request.locale.language}"/>_<c:out
value="${pageContext.request.locale.country}"/>
<br/><br/>
<fmt:formatNumbervalue=".51"type="percent"/>
</body>
</html>
Figure24-8showstheJSP'soutput.
Figure24-8.AJSPdisplaysanumberformattedasapercentage
SeeAlso
TheJavadocfortheNumberFormatclass:http://java.sun.com/j2se/1.4.1/docs/api/java/text/NumberFormat.html;Chapter23ontheJSTL;Recipe24.12onformattingpercentagesinaservlet.
Recipe24.13SettingtheLocalizationContextintheDeploymentDescriptor
Problem
YouwanttoconfigurethelocalizationcontextfortheJSTLtagsusedbyawebapplication.
Solution
Useacontext-paramelementintheapplication'sdeploymentdescriptor.
Discussion
AlocalizationcontextisasetofresourcessuchasResourceBundlesthatyourwebapplication'susetoprovidelocaleinformationforaJSP.IftheJSPisdisplayingtranslatedtext,itcanuseJSTLtags(suchasfmt:fmtMessage)thatdetecttheuser'slocale,andthensearcheswithinthelocalizationcontextforthepropertexttodisplay.
Setthelocalizationcontextwithacontext-paramelementinweb.xml.Theparameternamemustbejavax.servlet.jsp.jstl.fmt.localizationContext.ItsvalueisthefullyqualifiedbasenameoftheResourceBundlethatyouhaveinstalledinthewebapplication.Example24-14showsacontext-paramelementthatpointstotheResourceBundlewehaveusedthroughoutthischapter.
Addthistypeofelementtoyourdeploymentdescriptorasanalternative
tousingtheJSTLtagfmt:setBundleinsideJSPstospecifyaResourceBundle.
Example24-14.SettingthelocalizationcontextforJSTLtags
<!--Beginningofweb.xml-->
<context-param>
<param-name>
javax.servlet.jsp.jstl.fmt.localizationContext
</param-name>
<param-value>i18n.WelcomeBundle</param-value>
</context-param>
<!--Restofweb.xml-->
SeeAlso
Chapter23ontheJSTL;Recipe24.2ondetectingtheclientlocaleinaJSP;Recipe24.6onusingaResourceBundleinaJSP;Recipe24.8onformattingdates;Recipe24.10onformattingcurrencies;Recipe24.12onformattingpercentages.
Chapter25.UsingJNDIandEnterpriseJavaBeans
Introduction
Recipe25.1.ConfiguringaJNDIObjectinTomcat
Recipe25.2.AccessingtheTomcatJNDIResourcefromaServlet
Recipe25.3.AccessingtheTomcatJNDIResourcefromaJSP
Recipe25.4.ConfiguringaJNDIResourceinWebLogic
Recipe25.5.ViewingtheJNDITreeinWebLogic
Recipe25.6.AccessingtheWebLogicJNDIResourcefromaServlet
Recipe25.7.AccessingtheWebLogicJNDIResourcefromaJSP
Recipe25.8.AccessinganEJBUsingtheWebLogicJNDITree
Introduction
TheJavaNamingandDirectoryInterface(JNDI)isanAPIthatJavadevelopersusetoaccessnaminganddirectoryservices.TheseservicesaretechnologiesthatJavaprogramsusetostoreorbindobjectsforlateruse,aswellassearchforor"lookup"objectreferences.ThepurposeofJNDIistoseparatetheresponsibilityofmaintainingarepositoryofcommonlyusedobjectsfromthewidevarietyofJavaclassesthatusethoseobjects,includingservletsandJSPs.
ExamplesofJNDIservicesaretheRemoteMethodInvocationregistryandtheLightweightDirectoryAccessProtocol(LDAP).TheJNDIAPI,representedbythejavax.namingpackage,providesacommonimplementationforaccessingobjectsthatareboundtotheseservices.
Thejavax.namingpackageispartoftheJava21.3and1.4SoftwareDevelopmentKits(SDKs).
Eachofthesetechnologieshasanamingschemewithwhich"JNDIobjects"canbefound.Thestructureoftheseschemesisoftenhierarchical;youstartatthetopoftheJNDItree,thenworkyourwaydowntoeachofthebranchestofindwhatyouarelookingfor.UsingJNDI,Javaprogramsbeginwithan"initialcontext,"similartotheforwardslash(/)fromwhichUnixbeginstodescribethelocationofafile.The/representstherootofastoragemediumorharddisk;youcanfindtheUsersfolderatthetoplevelofthediskbyentering/Users.
InTomcat,theinitialcontextofitsbuilt-inJNDIimplementationistheaddressjava:comp/envalllookupsstartfromthere.Chapter21describeshowtoaccessajavax.sql.DatasourcefromaJNDIimplementationbystartingattheinitialcontextjava:comp/env,andthenlookinguptheDataSourceattheaddressjdbc/MyDataSource.AllDataSourcesare
storedunderjdbc,sothisishowJavacodeaccessesaDataSourcenamed"MyDataSource."Usingafilesystemanalogy,the"root"folderinTomcat'sJNDIstructureis"java:comp/env"andspecificDataSourcesarestoredunderthejdbcsubdirectory.
YoucanuseJNDItogetaccesstoanyJavaobject,notjustDataSources.ThischapterdescribeshowtostoreaJavaBeanusingTomcat'sJNDIimplementation,andthenlookupthebeanusingaservletorJSP.Thechapteralsodescribeshowtoconfigureamailsession(withajavax.mail.Sessionobject)usingBEAWebLogic'sJNDIimplementation,andthentogainaccesstothatmailsessionbyenablingaservletorJSPtosendemail.
AservletcanalsoaccessEnterpriseJavaBeans(EJBs)usingJNDI.
AnEJBisaJavaclassthatresidesinthe"businesstier"oftheJava2EnterpriseEditon(J2EE)multi-tierarchitecture.TheJ2EEincludesawebtiercontainingourfamiliarservletsandJSPs,andanEnterpriseInformationSystem(EIS)tierinvolvingdatabasesystems.Seethe"SeeAlso"sectionofRecipe25.8.
TheservletsorJSPsmayrepresentthepresentationlogicofasystemthatusesEJBstoaccessdatabasesandimplementtasksthatarespecifictoabusinessororganization.ThelastrecipeshowshowtoaccessanEJBfromaservletusingBEAWebLogicastheapplicationserver.
Recipe25.1ConfiguringaJNDIObjectinTomcat
Problem
YouwanttoconfigureaJavaBeanasaJNDIobjectusingTomcat4.
Solution
CreateResourceandResourceParamelementsinserver.xmlorintheXMLfilethatrepresentsyourwebapplication(locatedinTomcat'swebappsfolder).Thenaddaresource-env-refelementtoweb.xml.
Discussion
TheJNDIobjectforTomcatissetupinconf/server.xml.IfyouhaveconfiguredawebapplicationasaseparateXMLfileinTomcat'swebappsfolder,thenconfiguretheJNDIresourceinthisXMLfileinstead.Example25-1showsthesetupforbindingaJavaBeanasaJNDIobject.Thebeanisnamedcom.jspservletcookbook.StockPriceBean.
Example25-1.Theserver.xmlelementforconfiguringaJNDIobject
<Resourcename="bean/pricebean"type=
"com.jspservletcookbook.StockPriceBean"auth="Container"description=
"Awebharvestingbean"/>
<ResourceParamsname="bean/pricebean">
<parameter>
<name>factory</name>
<value>org.apache.naming.factory.BeanFactory</value>
</parameter>
</ResourceParams>
Example25-1includesaResourceelementandaResourceParamselementthatreferencestheResourcebyname("bean/pricebean").ThisnameistheaddressbywhichJavacodeaccessesabeaninstanceusingtheJNDIAPI.
Example25-2showstheresource-env-refelementthatmustappearinthedeploymentdescriptor(web.xml)inorderforwebapplicationcodetoaccesstheJNDIobject.Storethecom.jspservletcookbook.StockPriceBeanclassinWEB-INF/classesorinaJARfileplacedinWEB-INF/lib.
Example25-2.Placethiselementinthedeploymentdescriptorweb.xml
<!--startofdeploymentdescriptor-->
<resource-env-ref>
<description>
AfactoryforStockPriceBean
</description>
<resource-env-ref-name>
bean/pricebean
</resource-env-ref-name>
<resource-env-ref-type>
com.jspservletcookbook.StockPriceBean
</resource-env-ref-type>
</resource-env-ref>
<!--restofdeploymentdescriptor-->
Example25-3showsasnippetofcodethatusestheJNDIAPI,justtostartyouonhowtheconfigurationfitsinwithJNDI-relatedcode.
Example25-3.CodesnippetforaccessingaTomcatJNDIresource
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
//Thiscodemayappearinaservlet'sinit()methodorperhaps
//indoGet()ordoPost()
Contextenv=null;
StockPriceBeanspbean=null;
try{
env=(Context)newInitialContext().lookup("java:comp/env");
spbean=(StockPriceBean)env.lookup("bean/pricebean");
if(spbean==null)
thrownewServletException(
"bean/pricebeanisanunknownJNDIobject");
//closetheInitialContext
env.close();
}catch(NamingExceptionne){
//closetheContextifyou'renotusingitagain
try{env.close();}catch(NamingExceptionnex){}
thrownewServletException(ne);
}
Example25-3importsthenecessaryclassesfromthejavax.namingpackage.ThentwolookupstakeplacetogetareferencetoaJavaBeanthathasbeenboundtoaJNDIimplementation.Thefirstlookupprovidestheinitialcontext:
env=(Context)newInitialContext().lookup("java:comp/env");
ThesecondlookupattemptstoreturnaStockPriceBeanobject:
spbean=(StockPriceBean)env.lookup("bean/pricebean");
ThecodeclosestheInitialContexttoreleasetheobject'sresources,ifthecodeisnotgoingtousethecontextagainforanotherlookup.ThenextrecipeusescodelikethisfromservletsandJSPs.
SeeAlso
Recipe25.2onaccessingtheTomcatJNDIobjectfromaservlet;Recipe25.3onaccessingtheTomcatJNDIobjectfromaJSP;Chapter21onaccessingDataSourceswithJNDI.
Recipe25.2AccessingtheTomcatJNDIResourcefromaServlet
Problem
YouwanttoaccessaJNDIobjectwithaservletusingTomcat'sJNDIimplementation.
Solution
Usethejavax.namingclassesintheservlet'sinit()methodtolookupaJNDIobject.ThenusetheobjectinaservicemethodlikedoGet().
Discussion
AservletcanaccessaJavaBeanasaJNDIregisteredresourceafteryouhave:
1. DevelopedtheJavaBeanclassandstoreditinWEB-INF/classesorinaJARinWEB-INF/lib.
Changedtheserverconfigurationfileandweb.xmlasdescribedinRecipe25.1,inordertobindtheobjecttotheTomcatJNDItree.
Example25-4createsajavax.naming.InitialContextinitsinit()method,thenlooksupaJavaBean:com.jspservletcookbook.StockPriceBean.ThisbeanisboundtotheJNDIimplementationunderthename"bean/pricebean."Theinit()methodiscalledonlywhentheservletcontainercreatesaservlet
instance,sotheservlethasaccesstooneinstanceofStockPriceBean.
Example25-4.UsingaTomcatJNDIobjectfromaservlet
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassBeanServletextendsHttpServlet{
privateStockPriceBeanspbean;
publicvoidinit()throwsServletException{
Contextenv=null;
try{
env=(Context)newInitialContext().lookup("java:comp/env");
spbean=(StockPriceBean)env.lookup("bean/pricebean");
//closetheInitialContext,unlessthecodewilluseitfor
//anotherlookup
env.close();
if(spbean==null)
thrownewServletException(
"bean/pricebeanisanunknownJNDIobject");
}catch(NamingExceptionne){
try{env.close();}catch(NamingExceptionnex){}
thrownewServletException(ne);
}//try
}//init
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
//useaPrintWritertosendtextdatatotheclient
java.io.PrintWriterout=response.getWriter();
//BeginassemblingtheHTMLcontent
out.println("<html><head>");
out.println("<title>StockPriceFetcher</title></head><body>");
out.println("<h2>Pleasesubmitavalidstocksymbol</h2>");
//makesuremethod="POST"sothattheservletservicemethod
//callsdoPostintheresponsetothisformsubmit
out.println(
"<formmethod=\"POST\"action=\""+request.getContextPath()+
"/namingbean\">");
out.println("<tableborder=\"0\"><tr><tdvalign=\"top\">");
out.println("Stocksymbol:</td><tdvalign=\"top\">");
out.println("<inputtype=\"text\"name=\"symbol\"size=\"10\">");
out.println("</td></tr><tr><tdvalign=\"top\">");
out.println(
"<inputtype=\"submit\"value=\"SubmitInfo\"></td></tr>");
out.println("</table></form>");
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsjava.io.IOException{
Stringsymbol;//thiswillholdthestocksymbol
floatprice=0f;
symbol=request.getParameter("symbol");
booleanisValid=(symbol==null||symbol.length()<1)?
false:true;
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
//useaPrintWritersendtextdatatotheclient
java.io.PrintWriterout=response.getWriter();
//BeginassemblingtheHTMLcontent
out.println("<html><head>");
out.println("<title>Lateststockvalue</title></head><body>");
if((!isValid)||spbean==null){
out.println(
"<h2>Sorry,thestocksymbolparameterwaseither"+
"emptyornull</h2>");
}else{
out.println("<h2>Hereisthelatestvalueof"+symbol+"</h2>");
spbean.setSymbol(symbol);
price=spbean.getLatestPrice();
out.println((price==0?
"Thesymbolisprobablyinvalid.":""+price));
}
out.println("</body></html>");
}//doPost
}//BeanServlet
Example25-4callsclose()ontheInitialContexttofreeupanyresourcesthisobjectisusing,sincethecodedoesnotuseitagaintoinitiatealookup.ThentheservletusesthebeanobjecttoaccessalivestockquoteinitsdoGet()method.Theservletfirstcallsthebean'ssettermethodsetSymbol()tonotifythebeanaboutwhichstocksymbolitislookingup.
Example25-5showsthebeanthatTomcathasstoredasaJNDIobject(it'sthesamebeanusedinExample25-4).Chapter26explainsthisbean,which"scrapes"astockpriceoffofawebpage.Chapter26coversthebean'sdetails;themethodsthischapter'sservletusesaresetSymbol()andgetLatestPrice().Thebeanhandlesallthedetailsofdownloadingthestockprice.
Example25-5.ThebeanthatisstoredasaJNDIobject
packagecom.jspservletcookbook;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.net.URL;
importjava.net.MalformedURLException;
importjavax.swing.text.html.HTMLEditorKit.ParserCallback;
importjavax.swing.text.MutableAttributeSet;
importjavax.swing.text.html.parser.ParserDelegator;
publicclassStockPriceBean{
privatestaticfinalStringurlBase=
"http://finance.yahoo.com/q?d=t&s=";
privateBufferedReaderwebPageStream=null;
privateURLstockSite=null;
privateParserDelegatorhtmlParser=null;
privateMyParserCallbackcallback=null;
privateStringhtmlText="";
privateStringsymbol="";
privatefloatstockVal=0f;
publicStockPriceBean(){}//no-argumentsconstructorforthebean
publicvoidsetSymbol(Stringsymbol){
this.symbol=symbol;
}
publicStringgetSymbol(){
returnsymbol;
}
//Innerclassprovidesthecallback
classMyParserCallbackextendsParserCallback{
privatebooleanlastTradeFlag=false;
privatebooleanboldFlag=false;
publicMyParserCallback(){
if(stockVal!=0)
stockVal=0f;
}
publicvoidhandleStartTag(javax.swing.text.html.HTML.Tagt,
MutableAttributeSeta,intpos){
if(lastTradeFlag&&(t==javax.swing.text.html.HTML.Tag.B)){
boldFlag=true;
}
}//handleStartTag
publicvoidhandleText(char[]data,intpos){
htmlText=newString(data);
if(htmlText.indexOf("Nosuchtickersymbol.")!=-1){
thrownewIllegalStateException(
"InvalidtickersymbolinhandleText()method.");
}elseif(htmlText.equals("LastTrade:")){
lastTradeFlag=true;
}elseif(boldFlag){
try{
stockVal=newFloat(htmlText).floatValue();
}catch(NumberFormatExceptionne){
try{
//teaseoutanycommasinthenumberusingNumberFormat
java.text.NumberFormatnf=java.text.NumberFormat.
getInstance();
Doublef=(Double)nf.parse(htmlText);
stockVal=(float)f.doubleValue();
}catch(java.text.ParseExceptionpe){
thrownewIllegalStateException(
"Theextractedtext"+htmlText+
"cannotbeparsedasanumber!");
}//innertry
}//outertry
lastTradeFlag=false;
boldFlag=false;
}//if
}//handleText
}//MyParserCallback
publicfloatgetLatestPrice()throwsIOException,MalformedURLException{
stockSite=newURL(urlBase+symbol);
webPageStream=newBufferedReader(newInputStreamReader(stockSite.
openStream()));
htmlParser=newParserDelegator();
callback=newMyParserCallback();//ParserCallback
synchronized(htmlParser){
htmlParser.parse(webPageStream,callback,true);
}//sychronized
//resetsymbol
setSymbol("");
returnstockVal;
}//getLatestPrice
}//StockPriceBean
TheParserDelegator.parse()methodissynchronizedandthereforedesignedtoonlyallowonethreadatatimetoparsethewebpageandpulloutthestockquote.
Figure25-1showsthewebpageformgeneratedbytheservlet'sdoGet()method.Theuserentersastocksymbolintothisform,thensubmitstheformtotheservlet'sdoPost()method.
Figure25-1.Enterastocksymbolforalivestockprice
Figure25-2showsthestockinformationthattheJNDIobjectfoundfortheservlet.
Figure25-2.Theservlet'sdoPost()methodgeneratesalivestockquoteusingaJNDIobject
SeeAlso
Recipe25.1onconfiguringaJNDIobjectwithTomcat;Recipe25.3onaccessingtheTomcatJNDIobjectfromaJSP;Chapter21onaccessingDataSourceswithJNDI;Chapter26onharvestingwebinformation.
Recipe25.3AccessingtheTomcatJNDIResourcefromaJSP
Problem
YouwanttoaccessaJNDIresourcefromaJSP.
Solution
Useafiltertoplacetheobjectinrequestorsessionscope.AccesstheobjectintheJSPwiththec:setandc:outJSTLtags.
Discussion
AnicejobforafilterisaccessingaJNDIobject,thenplacingareferencetothatobjectinasessionforaJSPtouse.SeeChapter19formoreinformationonfilters.
HerearethestepsneededtouseafilterwithJNDIandaJSP:
1. Developandcompilethefilter,includingano-argumentsconstructor.
UsetheJNDIAPIandjavax.namingpackageinthefiltertosetasessionattributeusingtheJNDIobject.
PlacethefilterinWEB-INF/classesorinaJARinWEB-INF/lib.
Addfilterandfilter-mappingelementstoweb.xml;mapthefiltertotheJSPthatwillusetheJNDIobject(Example25-7).
CreateaJSPthatusesthesessionattribute.
Example25-6showsthefilter.Thefilterinitializesajavax.naming.Contexttypeinitsinit()method(whentheservletcontainercreatesthefilterinstance).ThedoFilter()methodgrabsaJNDIobjectandstorestheobjectasasessionattribute.ThefilterchainendsattheJSPtowhichthefilterismapped;therefore,theJSPhasaccesstothesessionattribute(i.e.,theJNDIobject).
Example25-6.AFilteraccessesaJNDIobjectandsetstheobjectasasessionattribute
packagecom.jspservletcookbook;
importjava.io.IOException;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassJndiTFilterimplementsFilter{
privateFilterConfigconfig;
privateContextenv;
//No-argumentsconstructorrequiredforafilter;we'vemadeit
//explicithere,eventhoughthecompilerwouldhavecreatedone
//intheabsenceofthisoranyotherconstructor
publicJndiTFilter(){}
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
this.config=filterConfig;
try{
env=(Context)newInitialContext().lookup("java:comp/env");
env.close();
}catch(NamingExceptionne){
try{env.close();}catch(NamingExceptionnex){}
thrownewServletException(ne);
}
}
publicvoiddoFilter(ServletRequestrequest,
ServletResponseresponse,FilterChainchain)throwsIOException,
ServletException{
StockPriceBeanspbean=null;
try{
spbean=(StockPriceBean)env.lookup("bean/pricebean");
}catch(NamingExceptionne){}
HttpServletRequesthRequest=null;
if(requestinstanceofHttpServletRequest)
hRequest=(HttpServletRequest)request;
HttpSessionhSession=hRequest.getSession();
if(hSession!=null)
hSession.setAttribute("MyBean",spbean);
chain.doFilter(request,response);
}//doFilter
publicvoiddestroy(){
/*calledbeforetheFilterinstanceisremoved
fromservicebythewebcontainer*/
}
}//Filter
Thefilter'sdoFilter()methodiscalledeachtimeaclientrequeststheJSP,soeachclientisassociatedwithadifferentbeaninstance.Inotherwords,eachsessionstoresitsownbeaninstance.
TheJSPcouldthenremovethesessionattribute(ifitwasnotgoingtobeusedagain)toconserveserverresources.SeeChapter16forrecipesonsettingandremovingsessionattributes.
Example25-7showsthefilterandfilter-mappingelementsthatyoucanaddtothedeploymentdescriptor.Thiscausestheservletcontainertocreateaninstanceofthefilter(callingthefilter'sinit()method).Thenthecontainercallsthefilter'sdoFilter()methodwheneveritreceivesarequestmatchingtheURL(s)associatedwiththefilter-mappingelement.
Example25-7.ThefilterandelementsforaJNDI-relatedfilter
<!--startofweb.xml-->
<filter>
<filter-name>JndiTFilter</filter-name>
<filter-class>com.jspservletcookbook.JndiTFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>JndiTFilter</filter-name>
<url-pattern>/jndiJsp.jsp</url-pattern>
</filter-mapping>
<!--restofweb.xml-->
Example25-7mapstheJndiTFiltertothewebcomponentattheURL/jndiJsp.jsp.Example25-8showstheJSPthatusesthesessionattribute,called"MyBean"todisplayastockquote.
Example25-8.AJSPusesasessionattributeoriginatingasaJNDIobject
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>JndiBean</title></head>
<body>
<h2>GettingaStockPriceBeanobjectviaJNDI...</h2>
<c:setvar="priceBean"value="${MyBean}"/>
<%--setthe'symbol'propertytothestocksymbol--%>
<c:settarget="${priceBean}"property="symbol"value="${param.symbol}"/>
<%--getthelatestpricebycallinggetLatestPrice()onthebeanobject--%>
Thelatestprice:<c:outvalue="${priceBean.latestPrice}"/>
</body>
</html>
Figure25-3showsthisJSP'soutput.Example25-5inRecipe25.2showsthecodefortheJavaBeanthatthisJSPuses.
Figure25-3.AJSPusesasessionattributeviaJNDItodisplayastockprice
SeeAlso
Recipe25.1onconfiguringaJNDIobjectwithTomcat;Recipe25.2onaccessingtheTomcatJNDIobjectfromaservlet;Chapter21onaccessingDataSourceswithJNDI.
Recipe25.4ConfiguringaJNDIResourceinWebLogic
Problem
YouwanttobindanobjecttoBEAWebLogic'sJNDIimplementation.
Solution
UsetheWebLogicAdministrationconsole.
Discussion
Herearethestepsneededtobindajavax.mail.Sessionobject(whichIuseasanexampleforthisrecipe)toWebLogic'sJNDIimplementation.TheadvantageofthisapproachisthattheavailableSessionisalreadyconfiguredwithelementssuchasitsSMTPhost(seeTable25-1).TheSessionis"readytogo"forthecodethatwilleventuallylookupandusetheobject.
1. LogintotheWebLogicAdministrationconsole,whichinvolvesusingabrowserURLsuchashttp://localhost:7001/console.
GotoYour-domain-name Services Mailinthelefthandcolumnmenu.
Clickon"ConfigureanewMailSession..."ThisproducesthewindowshowninFigure25-4.
Figure25-4.Configuringajavax.mail.SessiontypeasaJNDIobjectusingtheWebLogicAdministrationconsole
4. Fillinthetextfieldsintheresultingwindow.GivetheSessionobjectaJNDIname(under"JndiName"),whichisthenamethatthecodeusestolookuptheobject.
EnteranypropertiesfortheSessionbytypinginthepropertyname,anequalssign(=),andthepropertyvalue.SeeTable25-1.
Clickthe"Apply"button,thenchoosethe"Targets"tab.TheresultingscreenallowsyoutoassociatetheJNDIobjectwithoneormoreservers.
NowtheJNDIobjectisavailabletoJavaprogramsusingtheJNDIAPIandthenameyouboundtheobjectunder.Recipe25.5showshowtoviewtheJNDItreegraphicallytoverifythattheobjecthasbeenboundproperly.
Table25-1.JavaMailpropertiessetforthisrecipe'sSessionJNDIobject
Propertyname Description Example
mail.host Thedefaultmailserver mail.comcast.net
mail.smtp.host Protocol-specificmailhost;defaultstomail.hostvalue mail.comcast.net
mail.user Theusernameforconnectingtothemailserver bruceperry
mail.from Thereturnaddresstousewhensendingmail. [email protected]
SeeAlso
Recipe25.6onaccessingaJNDIobjectwithaservletonWebLogic;Recipe25.7onaccessingaJNDIobjectwithaJSPonWebLogic;Chapter2ononaccessingaJNDIobjectwithaJSPonWebLogic;Chapter2ondeployingwebcomponentswithWebLogic.
Recipe25.5ViewingtheJNDITreeinWebLogic
Problem
YouwanttoviewtheWebLogicJNDItreeingraphicalform.
Solution
RightclickontheservernameintheWebLogicAdministrationconsoleandchoose"ViewJNDITree."
Discussion
AfteryouhaveboundanobjecttoJNDIusingtheAdministrationconsole,youcanthenviewtheJNDItreetoseeifWebLogichasboundyourobjectasintended.Right-clickon"My-domain-name ServersServer-name"inthelefthandmenuandchoose"ViewJNDITree."ThisgeneratesanewbrowserwindowthatlooksliketheoneinFigure25-5.
Thenewobject("MyEmail")isrepresentedatthetopofthetreeasapurpledot.ThisisanicegraphicalwayofviewingthehierarchicalstructureoftheJNDItree,includingitssubdirectoriesandvariousobjects,thatareavailabletoaWebLogicserver.
Figure25-5showsthe"MyEmail"boundobjectselectedintheJNDItree.Informationabouttheobjectisdisplayedintherighthandframeofthebrowserwindow.
Figure25-5.AgraphicaldisplayoftheWebLogicJNDItree
SeeAlso
Recipe25.4onconfiguringaJNDIobjectonWebLogic;Recipe25.6onaccessingaJNDIobjectwithaservletonWebLogic;Recipe25.7onaccessingaJNDIobjectwithaJSPonWebLogic;Chapter2ondeployingwebcomponentswithWebLogic.
Recipe25.6AccessingtheWebLogicJNDIResourcefromaServlet
Problem
YouwanttoaccesstheJNDIobjectcreatedandboundonWebLogic.
Solution
UsetheJNDIAPIintheservlettoaccessareferencetotheboundobject.
Discussion
Example25-9isanHttpServletthatobtainsajavax.mail.SessionobjectfromWebLogic'sJNDIimplementation.Theservletusesthisobjecttobuildanemailmessage.TheservletinitiatestheJNDIlookupinitsinit()methodforanobjectboundunderthename"MyEmail"(Recipe25.4).Theservletcontainercallstheinit()oncewhenthecontainercreatestheservletinstance.
Example25-9.Servlettoobtainajavax.mail.SessionobjectfromWebLogic'sJNDIimplementationandbuildanemailmessage
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.mail.*;
importjavax.mail.internet.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassEmailJndiServletextendsHttpServlet{
privateSessionmailSession;
publicvoidinit()throwsServletException{
Contextenv=null;
try{
env=(Context)newInitialContext();
mailSession=(Session)env.lookup("MyEmail");
if(mailSession==null)
thrownewServletException(
"MyEmailisanunknownJNDIobject");
//closetheInitialContext
env.close();
}catch(NamingExceptionne){
try{env.close();}catch(NamingExceptionnex){}
thrownewServletException(ne);
}
}//init
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println(
"<html><head><title>Emailmessagesender</title></head><body>");
Stringto=request.getParameter("to");
Stringfrom=request.getParameter("from");
Stringsubject=request.getParameter("subject");
StringemailContent=request.getParameter("emailContent");
try{
sendMessage(to,from,subject,emailContent);
}catch(Exceptionexc){
thrownewServletException(exc.getMessage());
}
out.println(
"<h2>Themessagewassentsuccessfully</h2></body></html>");
out.println("</body></html>");
}//doPost
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//doGet()callsdoPost()
doPost(request,response);
}
privatevoidsendMessage(Stringto,Stringfrom,Stringsubject,
StringbodyContent)throwsException{
MessagemailMsg=null;
mailMsg=newMimeMessage(mailSession);//anewemailmessage
InternetAddress[]addresses=null;
try{
if(to!=null){
//throws'AddressException'ifthe'to'emailaddress
//violatesRFC822syntax
addresses=InternetAddress.parse(to,false);
mailMsg.setRecipients(Message.RecipientType.TO,addresses);
}else{
thrownewMessagingException(
"Themailmessagerequiresa'To'address.");
}
if(from!=null)
mailMsg.setFrom(from);
if(subject!=null)
mailMsg.setSubject(subject);
if(bodyContent!=null)
mailMsg.setText(bodyContent);
//Finally,sendthemailmessage;throwsa'SendFailedException'
//ifanyofthemessage'srecipientshaveaninvalidadress
Transport.send(mailMsg);
}catch(Exceptionexc){
throwexc;
}//sendMessage
}//EmailJndiServlet
ThedoPost()methodcallstheservlet'ssendMessage()method,passingintheemailmessagepartssuchastherecipientandtheemail'scontent.Theservletderivesthisinformationfromrequestparametersthattheusersubmits.Atypicalrequestfortheservletlookslike:
http://localhost:7001/[email protected]&
[email protected]&subject=hello&
emailContent=Awebmessage
AusercanalsoPOSTinformationtotheservletwithanHTMLform.
Theservlet'ssendMessage()methodusestheJNDIobjectinthejavax.mail.internet.MimeMessageconstructorwhenthemethodcreatesanewemailmessage.
Figure25-6showstheservlet'ssimplereturnmessageinabrowserwindow.
Figure25-6.Theservletsendstheemailsuccessfully
SeeAlso
Recipe25.4onconfiguringaJNDIobjectonWebLogic;Recipe25.5onviewingtheWebLogicJNDItreewiththeAdministrationconsole;Recipe25.7onaccessingaJNDIobjectwithaJSPonWebLogic;Chapter2ondeployingwebcomponentswithWebLogic.
Recipe25.7AccessingtheWebLogicJNDIResourcefromaJSP
Problem
YouwanttouseaWebLogicJNDIobjectinaJSP.
Solution
CreateafilterthataccessestheJNDIobjectandsetstheobjectasasessionattribute.
Discussion
Anysenseofdejávucomesfromafewrecipesago,whenyouusedafiltertopassaJNDIobjecttoaJSPonTomcat.TheonlydifferenceinthisrecipeisthattheapplicationserverusedisWebLogicandtheJNDIobjectisaJavaMailSession,notaJavaBean.
ThefilteraccessestheobjectusingtheJNDIAPIonWebLogic.Thenthefiltersetstheobjectasasessionattribute,sothattheJSPcanaccessthejavax.mail.Session.Example25-10showsthecodeforthefilterthatrecipeusesontheWebLogicserver.
Example25-10.AfilterstoresaWebLogicJNDIobjectinasessionattribute
packagecom.jspservletcookbook;
importjava.io.IOException;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassJndiFilterimplementsFilter{
privateFilterConfigconfig;
privateContextenv;
publicJndiFilter(){}
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
this.config=filterConfig;
try{
env=(Context)newInitialContext();
}catch(NamingExceptionne){
thrownewServletException(ne);
}
}//init
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsIOException,ServletException{
javax.mail.SessionmailSession=null;
try{
mailSession=(javax.mail.Session)env.lookup("MyEmail");
}catch(NamingExceptionne){}
HttpServletRequesthRequest=null;
if(requestinstanceofHttpServletRequest){
hRequest=(HttpServletRequest)request;
HttpSessionhSession=hRequest.getSession();
if(hSession!=null)
hSession.setAttribute("MyEmail",mailSession);
}//if
chain.doFilter(request,response);
}//doFilter
publicvoiddestroy(){
/*calledbeforetheFilterinstanceisremoved
fromservicebythewebcontainer*/
}
}
Example25-11showsthefilterconfigurationinsidethedeploymentdescriptor.ThisdeploymentdescriptormustaccompanyawebapplicationthatyouoranotherdeployerhasinstalledonWebLogicserver.
Example25-11.AfilterthataccessesaJNDIobjectonWeblogic
<!--startofweb.xml-->
<filter>
<filter-name>JndiFilter</filter-name>
<filter-class>com.jspservletcookbook.JndiFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>JndiFilter</filter-name>
<url-pattern>/jndiJsp.jsp</url-pattern>
</filter-mapping>
<!--restofweb.xml-->
Example25-12showsaJSPthataccessestheJNDIobject.Thiscodedisplaystheclassnameoftheobject,ajavax.mail.SessiontypethatRecipe25.4boundasaJNDIobjectonWebLogic.ThefilterinExample25-11thensettheobjectasasessionattribute(nottobeconfusedwiththeSessiontypeoftheobject).Thisattributeisavailabletoallwebcomponentsthatparticipateinthesamesession.Therefore,thec:settaginthisJSPusesthefollowingELcodetogetaccesstotheattribute.
${MyEmail}
Thenthec:outtagdisplaystheclassnameofthesessionattribute,inordertoverifythattheobjectisajavax.mail.Session.Recipe25.6givesthecompleteJavaMailcodeforsendinganemail.
Example25-12.TheJSPaccessestheJavaMailobjectasasessionattribute
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>JndiEmail</title></head>
<body>
<h2>Gettingajavax.mail.SessionobjectviaJNDI...</h2>
<c:setvar="mSession"value="${MyEmail}"/>
<c:outvalue="${mSession.class.name}"/>
</body>
</html>
Figure25-7showsawebbrowserwindowafterauserhasrequestedtheJSP.
Figure25-7.AJSPaccessesaJNDIobjectviaaservletfilter
SeeAlso
Chapter19onfilters;Chapter23ontheJSTL;Recipe25.4onconfiguringaJNDIobjectwithWebLogic;Recipe25.6onaccessingaJNDIobjectwithaservletonWebLogic;Chapter2ondeployingwebcomponentswithWebLogic.
Recipe25.8AccessinganEJBUsingtheWebLogicJNDITree
Problem
YouwanttoaccessanEnterpriseJavaBean(EJB)fromaservletonWebLogic.
Solution
FindouttheEJB'sJNDInameandusethejavax.namingpackagetogetareferencetotheEJBObjectorremoteinterfacesothatyoucancalltheEJB'smethods.
Discussion
AservletaccessesanEJBbyusingaspecifiedJNDIname.Theprocessisthereforetransparenttotheservletdeveloper.AnyEJBsanapplicationusescomprisethebusinesstierofanapplication.TheservletsandJSPsrepresentthewebtierwithinthemulti-tiereddistributedarchitectureofatypicalJava2EnterpriseEdition(J2EE)application.AllyouneedtoknowistheJNDInameassociatedwiththeEJBinordertousetheEJBinyourprograms.
EnterpriseJavaBeansisacomprehensivetopic;however,thisrecipeisdevotedtoshowinghowaservletcanconnecttoanEJB.The"SeeAlso"segmentofthisrecipeincludesseverallinkstoEJBandJ2EEinformationandbooks.
YoushouldbeawareoftheEJB'sbusinessmethods,butdonothavetobeanexpertonthejavax.ejbpackagetousetheEJB.Example25-13showsthesourcecodeforastatelesssessionEJBthatismanagedbyBEAWebLogic7.0applicationserver.
AcertaintypeofEJB,astatelesssessionbeanencapsulatesbusinesslogicthatdoesnotrequirepersistenceorthesavingoftheobject'sstatebetweenmethodcalls.Ontheotherhand,astatefulsessionbean(suchasashoppingcartobject),mustremembertheobject'sstate(suchasthevalueofvariousinstancevariables)betweenmethodcalls,aspartofaconversationwiththeEJBclient.
Example25-13providesajava.util.MapthatlinksU.S.statenameswiththeirpostalabbreviations.Thesessionbeanincludesonebusinessmethod,getAbbreviation(),whichreceivesastatenameasaparameterandreturnsitspostalabbreviation.
Example25-13.ThestatelesssessionEJB
packagecom.jspservletcookbook;
importjavax.ejb.*;
importjava.util.Map;
importjava.util.HashMap;
publicclassAbbrevBeanimplementsSessionBean{
privateSessionContextcontext;
privateMapabbrevMap;
publicAbbrevBean(){//thebean'sno-argumentsconstructor
//AMapcontainingthenamesofstatesandabbreviations
abbrevMap=newHashMap();
abbrevMap.put("ALABAMA","AL");
abbrevMap.put("ALASKA","AK");
abbrevMap.put("AMERICANSAMOA","AS");
abbrevMap.put("ARIZONA","AZ");
abbrevMap.put("ARKANSAS","AR");
abbrevMap.put("CALIFORNIA","CA");
abbrevMap.put("COLORADO","CO");
abbrevMap.put("CONNECTICUTT","CT");
abbrevMap.put("DELAWARE","DE");
abbrevMap.put("DISTRICTOFCOLUMBIA","DC");
abbrevMap.put("FEDERATEDSTATESOFMICRONESIA","FM");
abbrevMap.put("FLORIDA","FL");
abbrevMap.put("GEORGIA","GA");
abbrevMap.put("GUAM","GU");
abbrevMap.put("HAWAII","HI");
abbrevMap.put("IDAHO","ID");
abbrevMap.put("ILLINOIS","IL");
abbrevMap.put("INDIANA","IN");
abbrevMap.put("IOWA","IA");
abbrevMap.put("KANSAS","KS");
abbrevMap.put("KENTUCKY","KY");
abbrevMap.put("LOUISIANA","LA");
abbrevMap.put("MAINE","ME");
abbrevMap.put("MARSHALLISLANDS","MH");
abbrevMap.put("MARYLAND","MD");
abbrevMap.put("MASSACHUSETTS","MA");
abbrevMap.put("MICHIGAN","MI");
abbrevMap.put("MINNESOTA","MN");
abbrevMap.put("MISSISSIPPI","MS");
abbrevMap.put("MISSOURI","MO");
abbrevMap.put("MONTANA","MT");
abbrevMap.put("NEBRASKA","NE");
abbrevMap.put("NEVADA","NV");
abbrevMap.put("NEWHAMPSHIRE","NH");
abbrevMap.put("NEWJERSEY","NJ");
abbrevMap.put("NEWMEXICO","NM");
abbrevMap.put("NEWYORK","NY");
abbrevMap.put("NORTHCAROLINA","NC");
abbrevMap.put("NORTHDAKOTA","ND");
abbrevMap.put("NORTHERNMARIANAISLANDS","MP");
abbrevMap.put("OKLAHOMA","OK");
abbrevMap.put("OREGON","OR");
abbrevMap.put("PALAU","PW");
abbrevMap.put("PENNSYLVANIA","PA");
abbrevMap.put("PUERTORICO","PR");
abbrevMap.put("RHODEISLAND","RI");
abbrevMap.put("SOUTHCAROLINA","SC");
abbrevMap.put("SOUTHDAKOTA","SD");
abbrevMap.put("TENNESSEE","TN");
abbrevMap.put("TEXAS","TX");
abbrevMap.put("UTAH","UT");
abbrevMap.put("VERMONT","VT");
abbrevMap.put("VIRGINISLANDS","VI");
abbrevMap.put("VIRGINIA","VA");
abbrevMap.put("WASHINGTON","WA");
abbrevMap.put("WESTVIRGINIA","WV");
abbrevMap.put("WISCONSIN","WI");
abbrevMap.put("WYOMING","WY");
}//constructor
publicvoidsetSessionContext(SessionContextctx)throws
EJBException{
context=ctx;
}//setSessionContext
publicMapgetAbbrevMap(){
returnabbrevMap;
}
//Thebean'sbusinessmethod
publicStringgetAbbreviation(Stringstate){
return(String)abbrevMap.get(state);
}
//javax.ejb.SessionBeanmethod;ithastobeimplementedinasession
//bean,butisnotrelevanttoStatelesssessionbeans.
publicvoidejbActivate(){}
//javax.ejb.SessionBeanmethod;ithastobeimplementedinaSession
//bean,butisnotrelevanttostatelesssessionbeans.
publicvoidejbPassivate(){}
//javax.ejb.SessionBeanmethod;
publicvoidejbRemove(){}
}
Example25-13couldeasilybeimplementedasanordinaryJavahelperorutilityclass.However,IshowasimpleexampleofanEJBsothattherecipecanfocusonhowaservletconnectstotheseobjects.
EJBshaveadeploymentdescriptor,similartotheweb.xmlfilethatwebapplicationsuse.TheEJBdeploymentdescriptormustbenamedejb-jar.xml.WhenyoupackagetheEJB(s)beforetheyaredeployedonanapplicationserver,includethisdeploymentdescriptoraspartofthearchive.Theejb-jar.xmlfiledescribestherelatedEJBcomponent(s);theapplicationserverusesthisdescriptiveinformationinordertoproperlydeploytheEJB.
Forexample,theejb-jar.xmlfileinExample25-14specifiesthetypeof
EJB(e.g.,statelesssessionbean)andthefullyqualifiedclassnamesofitsrelatedJavaclasses,suchasitsremoteinterface.
Example25-14.Theejb-jar.xmlfile
<?xmlversion="1.0"?>
<!DOCTYPEejb-jarPUBLIC"-//SunMicrosystems,Inc.
//DTDEnterpriseJavaBeans2.0//EN"
"http://java.sun.com/dtd/ejb-jar_2_0.dtd"
>
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>AbbreviationEjb</ejb-name>
<home>com.jspservletcookbook.AbbrevHome</home>
<remote>com.jspservletcookbook.Abbrev</remote>
<local-home>com.jspservletcookbook.AbbrevLocalHome</local-home>
<local>com.jspservletcookbook.AbbrevLocal</local>
<ejb-class>com.jspservletcookbook.AbbrevBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
</ejb-jar>
ThepackagethatcontainsthisEJB,andwithwhichtheEJBisdeployedontheapplicationserver,isaJARfilenamedmyejb.jar(justanameIconcocted;youdonothavetousethesamename).
SincethisstatelesssessionbeanisdeployedonBEAWebLogicServer,theJARfilemustincludeavendor-specificdeploymentdescriptornamedweblogic-ejb-jar.xml.ThisdeploymentdescriptorgivesthedeployertheopportunitytoconfigureseveralaspectsofhowtheEJBisdeployedonWebLogic,suchastheJNDInamesofitshomeandlocalhome
interfaces.
The"home"objectisanimplementationofthe"home"interface,andthe"localhome"objectisanimplmentationofthelocalhomeinterface.Theseobjectsare"factories"forEJBobjects,whichdelegatethebusiness-methodcallstotheEJBdeployedintheserver.AfactoryisaJavaclassthatgeneratesobjectsofadifferentkindofJavaclass.Inthisrecipe'scase,theclientusesJNDItogetareferencetothehomeobject,whichcreatesanEJBobject.Theservlet(client)thencallstheEJBobject'sgetAbbreviation()method;theEJBobjectisaremoteobjector"stub"thatdelegatesthismethodcalltotheoriginalEJBstoredontheserver.
Youwillencounterthehomeobject'sJNDInameintheservletdepictedlateroninthisrecipe.
WhenyoudeployanEJBonWebLogicusingtheAdministrationConsole,WebLogicautomaticallybindsthehomeandlocalhomeobjectswithintheWebLogicJNDItree,usingthenamesspecifiedbytheweblogic-ejb-jar.xmldeploymentdescriptor.
Example25-15showstheweblogic-ejb-jar.xmldeploymentdescriptorforourstatelesssessionbean.
Example25-15.Theweblogic-ejb-jar.xmlfile
<!DOCTYPEweblogic-ejb-jarPUBLIC
'-//BEASystems,Inc.//DTDWebLogic7.0.0EJB//EN'
'http://www.bea.com/servers/wls700/dtd/weblogic-ejb-jar.dtd'>
<weblogic-ejb-jar>
<weblogic-enterprise-bean>
<ejb-name>AbbreviationEjb</ejb-name>
<stateless-session-descriptor>
<pool>
<initial-beans-in-free-pool>1</initial-beans-in-free-pool>
</pool>
</stateless-session-descriptor>
<jndi-name>AbbrevHome</jndi-name>
<local-jndi-name>AbbrevLocalHome</local-jndi-name>
</weblogic-enterprise-bean>
</weblogic-ejb-jar>
AnEJBmoduleisacomplicatedpackagethatincludesbeanclasses,remoteinterfaces,andtwodifferentdeploymentdescriptors.Example25-16showsthecontentsofthemyejb.jarfile.Iusethejartvfmyejb.jar.commandinacommand-linewindowtodisplaythecontentsofthespecifiedJARfile(itworksinbothUnixandWindows).
Example25-16.Thecontentsoftheejb-jar.xmlfile
H:\book\cookbook\code\chap27\src\ejbs\ejbjar>jartvfmyejb.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/jspservletcookbook/
com/jspservletcookbook/Abbrev.class
com/jspservletcookbook/AbbrevBean.class
com/jspservletcookbook/AbbrevHome.class
com/jspservletcookbook/AbbrevLocal.class
com/jspservletcookbook/AbbrevLocalHome.class
META-INF/ejb-jar.xml
META-INF/weblogic-ejb-jar.xml
InExample25-16,thesessionbeanisAbbrevBean.class,theremoteinterfaceisAbbrev.class,andthehomeobject(thefactoryforEJBobjectsthatimplementtheAbbrevinterface)isAbbrevHome.class.
Finally,Example25-17showstheservletthatusesthesessionbeanfromExample25-13.Thecodeisself-explanatory.TheimportantthingtorememberisthattheservletreceiveseareferencetotheAbbrevHomeobjectfromtheWebLogicJNDItree.Thentheservlet,initsdoGet()method,callstheAbbrevHomeobject'screate()methodtogetaninstanceofthesessionbean'sremoteinterface(inthisexample,it'sanAbbrevtype).
Example25-17.AservletthataccessestheEJBonWebLogicusingJNDI
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importjavax.rmi.PortableRemoteObject;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassWebJndiServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//Therequestparameterlookslike'state=Massachusetts'
Stringstate=request.getParameter("state");
Contextenv=null;
Abbrevabbrev=null;
AbbrevHomehome=null;
try{
env=(Context)newInitialContext();
//LookupthehomeorfactoryobjectontheWebLogicJNDItree
ObjectlocalH=env.lookup("AbbrevHome");
//ThismethodcallisnecessaryforEJBcodethatusesa
//technologycalledRMI-IIOP
home=(AbbrevHome)PortableRemoteObject.narrow(localH,
AbbrevHome.class);
//closetheInitialContext
env.close();
if(home==null)
thrownewServletException(
"AbbrevHomeisanunknownJNDIobject");
//Gettheremoteinterfacebycallingthehomeobject'screate()
//method
abbrev=(Abbrev)PortableRemoteObject.narrow(home.create(),
Abbrev.class);
}catch(NamingExceptionne){
try{env.close();}catch(NamingExceptionnex){}
thrownewServletException(ne);
}catch(javax.ejb.CreateExceptionce){
thrownewServletException(ce);
}
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head>");
out.println("<title>Stateabbreviations</title></head><body>");
out.println("<h2>Hereisthestate'sabbreviation</h2>");
//CalltheEJBObject'sgetAbbreviation()method;theEJBObject
//delegatesthismethodcalltothesessionbean.Puttherequest
//parameterinallupper-case,becausethisishowthesessionbean's
//java.util.Mapstoresthestatenames,whicharetheMap'skeys
if(state!=null)
out.println(abbrev.getAbbreviation(state.toUpperCase()));
try{
//TheservletisthroughwiththeEJBObject;callitsremove()
//method
abbrev.remove();
}catch(javax.ejb.RemoveExceptionre){}
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
doGet(request,response);
}//doPost
}//WebJndiServlet
Thevalueoftheabbreviationforastatesuchas"Oregon"isultimatelyretrievedontheserversidebycallingthesessionbean's
getAbbreviation()method.Figure25-8showsawebbrowserwindowafterauserhasrequestedtheservlet.TheURLlookssomethinglikehttp://localhost:7001/webjndi?state=Oregon.TheURLpattern/webjndiismappedinweb.xmltotheservletofExample25-17.
Figure25-8.AnEJB-accessingservlet'swebbrowserdisplay
SeeAlso
Recipe25.4onconfiguringaJNDIobjectwithWebLogic;Recipe25.6onaccessingaJNDIobjectwithaservletonWebLogic;Chapter2ondeployingwebcomponentswithWebLogic;aweblinkforthejavax.ejbAPI:http://java.sun.com/j2ee/1.4/docs/api/javax/ejb/package-summary.html;thedocumentationpageforWebLogicServer7.0:http://edocs.bea.com/wls/docs70/index.html;alinktoJ2EEtutorials,includinganEnterpriseJavaBeantutorial:http://java.sun.com/j2ee/tutorial/index.html;EnterpriseJavaBeans,ThirdEdition(O'Reilly);J2EEDesignPatterns(O'Reilly).
Chapter26.HarvestingWebInformationIntroduction
Recipe26.1.ParsinganHTMLPageUsingthejavax.swing.textSubpackages
Recipe26.2.UsingaServlettoHarvestWebData
Recipe26.3.CreatingaJavaBeanasaWebPageParser
Recipe26.4.UsingtheWebPageParsingJavaBeaninaServlet
Recipe26.5.UsingtheWebPageParsingJavaBeaninaJSP
Introduction
TheWebcontainsinformationgalore.Muchofthisinformationisfreelyavailablebysimplysurfingovertoanorganization'swebsiteandreadingtheirpagesorsearchresults.However,itcanbedifficultseparatingthedrossfromthegems.Thevastmajorityofawebpage'svisualcomponentsaretypicallydedicatedtomenus,logos,advertisingbanners,andfancyappletsorFlashmovies.WhatifallyouareinterestedinisatinynuggetofdataawashinanoceanofHTML?
TheanswerliesinusingJavatoparseawebpagetoextractonlycertainpiecesofinformationfromit.Thewebtermsforthistaskareharvestingorscrapinginformationfromawebpage.Perhapswebservices(Chapter27)willeventuallyreplacetheneedtoharvestwebdata.ButuntilmostmajorsiteshavetheirwebservicesAPIsupandrunning,youcanuseJavaandcertainjavax.swing.textsubpackagestopullspecifiedtextfromwebpages.
Howdoesitwork?Basically,yourJavaprogramusesHTTPtoconnectwithawebpageandpullinitsHTMLtext.
ParsingtheHTMLfromwebsitesstillinvolvestransferringtheentirewebpageoverthenetwork,evenifyouareonlyinterestedinafractionofitsinformation.Thisiswhyusingwebservicesisamuchmoreefficientmannerofsharingspecificdatafromawebsite.
ThenuseJavacodetoparsetheHTMLpageinordertopullfromitonlythepieceofdatayouareinterestedin,suchasweatherdataorastockquote.ThefollowingrecipesshowtheJavaclassesthatyoucanusetoharvestwebinformation.ThentherecipesshowaservletandaJSPusingaJavaBeantograbanddisplay,asanexample,alivestockquote.
Recipe26.1ParsinganHTMLPageUsingthejavax.swing.textSubpackages
Problem
YouwanttousetheclassestheJava2StandardEdition(J2SE)makesavailableforparsingHTML.
Solution
Usethevarioussubpackagesofthejavax.swing.textpackagetocreateaparserforHTML.
Discussion
TheJ2SE1.3and1.4versionsincludethenecessaryclassesforsiftingthroughwebpagesinsearchofinformation.TheJavaprogramstheserecipesuseimportthefollowingclasses:
javax.swing.text.html.
HTMLEditorKit.ParserCallback;
javax.swing.text.MutableAttributeSet;
javax.swing.text.html.parser.ParserDelegator;
Thedesignpatternthattheseclassesusetoreadwebpagesinvolvesthreemainelements:
1. Ajava.net.URLobjectthatopensupasocketorInputStreamtothewebpageusingHTTP.Thecodethenusesthisobjecttoreadthewebpage.
AParserDelegatorobjectwithwhichthecodesiftsthroughthewebpagebycallingthisobject'sparse()method.
AParserCallbackobjectthattheParserDelegatorusestotakecertainactionswhileitisparsingthewebpage'sHTMLtext.AcallbackingeneralisanobjectthatJavacodetypicallypassesintoanotherobject'sconstructor.Theenclosingobjectthendrivesthecallbackbyinvokingthecallback'smethods,whichtheJavaprogrammerimplementsaccordingtowhattheywanttoaccomplishbyparsingtheHTML.Theroleofthecallbackwillbecomeclearerasyoureadthroughtheserecipes.
TheservletandJavaBeandefinedinthischapteruseaninnerclasstoimplementthecallback.Example26-1showsthecallbackthatextendsjavax.swing.text.html.HTMLEditorKit.ParserCallback.
Example26-1.Acallbackclassforsiftingthroughwebpages
classMyParserCallbackextendsParserCallback{
//breadcrumbsthatleadustothestockprice
privatebooleanlastTradeFlag=false;
privatebooleanboldFlag=false;
publicMyParserCallback(){
//Resettheenclosingclass'stock-priceinstancevariable
if(stockVal!=0)
stockVal=0f;
}
//Amethodthattheparsercallseachtimeitconfrontsastarttag
publicvoidhandleStartTag(javax.swing.text.html.HTML.Tagt,
MutableAttributeSeta,intpos){
if(lastTradeFlag&&(t==javax.swing.text.html.HTML.Tag.B)){
boldFlag=true;
}
}//handleStartTag
//Amethodthattheparsercallseachtimeitreachesnestedtextcontent
publicvoidhandleText(char[]data,intpos){
htmlText=newString(data);
if(htmlText.indexOf("Nosuchtickersymbol.")!=-1){
thrownewIllegalStateException(
"InvalidtickersymbolinhandleText()method.");
}elseif(htmlText.equals("LastTrade:")){
lastTradeFlag=true;
}elseif(boldFlag){
try{
stockVal=newFloat(htmlText).floatValue();
}catch(NumberFormatExceptionne){
try{
//teaseoutanycommasinthenumberusingNumberFormat
java.text.NumberFormatnf=java.text.NumberFormat.
getInstance();
Doublef=(Double)nf.parse(htmlText);
stockVal=(float)f.doubleValue();
}catch(java.text.ParseExceptionpe){
thrownewIllegalStateException(
"Theextractedtext"+htmlText+
"cannotbeparsedasanumber!");
}//try
}//try
//Resettheinnerclass'sinstancevariables
lastTradeFlag=false;
boldFlag=false;
}//if
}//handleText
}//MyParserCallback
Acallbackincludesmethodsthatrepresenttheattainmentofacertainelementofawebpageduringtheparsingprocess.Forexample,theparser(theobjectthatenclosesthecallbackobject)callshandleStartTag()wheneveritrunsintoanopeningtagasittraversesthewebpage.Examplesofopeningtagsare<html>,<title>,or<body>.Therefore,whenyouimplementthehandleStartTag()methodinthecode,youcancontrolwhatyourprogramdoeswhenitfindsanopeningtag,suchas"preparetograbthetextthatappearswithintheopeningandclosingtitletag."
Example26-1usesaparticularalgorithmtosearchawebpageforanupdatedstockquote,andthisiswhatthetwomethods(handleStartTag()andhandleText())accomplishintheMyParserCallbackclass:
1. Itlooksforthetext"LastTrade"inthehandleText()callbackmethod;ifit'sfound,thelastTradeFlagbooleanvariableissettotrue.Thisislike"droppingabreadcrumb"astheprogramtravelsthroughthevastHTMLofthewebpage.
IfhandleStartTag()findsabtagrightafter"LastTrade"isfound(thelastTradeFlagflagistrue),itgrabsthenestedcontentofthatbtag,becausethiscontentrepresentsthestockquote.
Thebignegativeofwebharvesting,whichwebservicesispartlydesignedtosolve,isthatwhenthewebpageyouareparsingischanged,yourprogramthrowsexceptionsandnolongerpullsouttheinformation,becauseitsalgorithmsarebasedontheoldpagestructure.
Example26-2showsasnippetofcodethatusestheParserDelegator
andMyParserCallbackobjects,justtogiveyouanideaofhowtheyfittogetherbeforewemoveontotheservletandJSP.
Example26-2.Acodesnippetshowstheparserandcallbackclassesatwork
//Instancevariables
privateParserDelegatorhtmlParser=null;
privateMyParserCallbackcallback=null;
//InitializeaBufferedReaderandaURLinsideofamethodforconnecting
//toandreadingawebpage
BufferedReaderwebPageStream=null;
URLstockSite=newURL(BASE_URL+symbol);
//Connectinsideofamethod
webPageStream=newBufferedReader(
newInputStreamReader(stockSite.openStream()));
//Createtheparserandcallback
htmlParser=newParserDelegator();
callback=newMyParserCallback();//ParserCallback
//Callparse(),passingintheBufferedReaderandcallbackobjects
htmlParser.parse(webPageStream,callback,true);
Theparse()methodofParserDelegatoriswhattriggersthecallingofthecallback'smethods,withthecallbackpassedinasanargumenttoparse().
Nowlet'sseehowtheseclassesworkinaservlet,JavaBean,andJSP.
SeeAlso
AJavadoclinkforParserDelegator:http://java.sun.com/j2se/1.4.1/docs/api/javax/swing/text/html/parser/ParserDelegator.htmlChapter27onusingwebservicesAPIstograbinformationfromwebservers.
Recipe26.2UsingaServlettoHarvestWebData
Problem
Youwanttouseaservlettoharvestwebinformation.
Solution
UsetheHTMLparsingAPIclassesoftheJava2SoftwareDevelopmentKit(SDK).
Discussion
Thelastrecipeintroducedtherelevantsubpackagesofthejavax.swing.textpackage;thisiswhereIshowhowtousetheminaservlet.Example26-3importsthenecessaryclassestoparseanHTMLpage.Theservlet'sdoGet()methoddisplaysaforminwhichtheuserentersastocksymbol(suchas"INTC,"caseinsensitive).
ThenthedoPost()methodattemptstogetalivestockquoteforthatsymbolbyparsingawebpagefromfinance.yahoo.com.
Example26-3.Harvestingwebdatafromaservlet
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.io.BufferedReader;
importjava.io.InputStreamReader;
importjava.net.URL;
importjava.net.MalformedURLException;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjavax.swing.text.html.HTMLEditorKit.ParserCallback;
importjavax.swing.text.MutableAttributeSet;
importjavax.swing.text.html.parser.ParserDelegator;
publicclassHtmlParseServletextendsHttpServlet{
privatestaticfinalStringBASE_URL="http://finance.yahoo.com"+
"/q?d=t&s=";
privateParserDelegatorhtmlParser=null;
privateMyParserCallbackcallback=null;
privateStringhtmlText="";
privatebooleanlastTradeFlag=false;
privatebooleanboldFlag=false;
privatefloatstockVal=0f;
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,
java.io.IOException{
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
//useaPrintWritertosendtext
java.io.PrintWriterout=response.getWriter();
//BeginassemblingtheHTMLcontent
out.println("<html><head>");
out.println("<title>StockPriceFetcher</title></head><body>");
out.println("<h2>Pleasesubmitavalidstocksymbol</h2>");
//makesuremethod="post"sothattheservletservicemethod
//callsdoPostintheresponsetothisformsubmit
out.println(
"<formmethod=\"post\"action=\""+request.getContextPath()+
"/stockservlet\">");
out.println("<tableborder=\"0\"><tr><tdvalign=\"top\">");
out.println("Stocksymbol:</td><tdvalign=\"top\">");
out.println("<inputtype=\"text\"name=\"symbol\"size=\"10\">");
out.println("</td></tr><tr><tdvalign=\"top\">");
out.println(
"<inputtype=\"submit\"value=\"SubmitInfo\"></td></tr>");
out.println("</table></form>");
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsjava.io.IOException{
Stringsymbol;//thiswillholdthestocksymbol
floatprice;//Thestock'slatestprice
symbol=request.getParameter("symbol");
booleanisValid=(symbol==null||symbol.length()<1)?
false:true;
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
//BeginassemblingtheHTMLcontent
out.println("<html><head>");
out.println("<title>Lateststockvalue</title></head><body>");
if(!isValid){
out.println(
"<h2>Sorry,thestocksymbolparameterwaseitherempty"+
"ornull</h2>");
}else{
out.println("<h2>Hereisthelatestvalueof"+symbol+"</h2>");
price=getLatestPrice(symbol);
out.println((price==0?"Thesymbolisprobablyinvalid.":
""+price));
}
out.println("</body></html>");
}//doPost
privatefloatgetLatestPrice(Stringsymbol)throwsIOException,
MalformedURLException{
BufferedReaderwebPageStream=null;
URLstockSite=newURL(BASE_URL+symbol);
webPageStream=newBufferedReader(newInputStreamReader(stockSite.
openStream()));
htmlParser=newParserDelegator();
callback=newMyParserCallback();
//thecodeisdesignedtomakecallingparse()thread-safe
synchronized(htmlParser){
htmlParser.parse(webPageStream,callback,true);
}//synchronized
returnstockVal;
}//getLatestPrice
classMyParserCallbackextendsParserCallback{
//breadcrumbsthatleadustothestockprice
privatebooleanlastTradeFlag=false;
privatebooleanboldFlag=false;
publicMyParserCallback(){
//Resettheenclosingclass'instancevariable
if(stockVal!=0)
stockVal=0f;
}
publicvoidhandleStartTag(javax.swing.text.html.HTML.Tagt,
MutableAttributeSeta,intpos){
if(lastTradeFlag&&(t==javax.swing.text.html.HTML.Tag.B)){
boldFlag=true;
}
}//handleStartTag
publicvoidhandleText(char[]data,intpos){
htmlText=newString(data);
if(htmlText.indexOf("Nosuchtickersymbol.")!=-1){
thrownewIllegalStateException(
"InvalidtickersymbolinhandleText()method.");
}elseif(htmlText.equals("LastTrade:")){
lastTradeFlag=true;
}elseif(boldFlag){
try{
stockVal=newFloat(htmlText).floatValue();
}catch(NumberFormatExceptionne){
try{
//teaseoutanycommasinthenumberusing
//NumberFormat
java.text.NumberFormatnf=java.text.NumberFormat.
getInstance();
Doublef=(Double)nf.parse(htmlText);
stockVal=(float)f.doubleValue();
}catch(java.text.ParseExceptionpe){
thrownewIllegalStateException(
"Theextractedtext"+htmlText+
"cannotbeparsedasanumber!");
}//try
}//try
lastTradeFlag=false;
boldFlag=false;
}//if
}//handleText
}//MyParserCallback
}//HttpServlet
TheMyParserCallbackinnerclassdefinestheparsingalgorithmfortheservlet,whichisexplainedinRecipe26.1.ThegetLatestPrice()methodusesthiscallbackclassandanHTMLparsertoreturnastockquoteasafloattype.
TheParserDelegatorobjectissynchronizedasitcallsparse(),sothatonlyonethreadisparsingthewebpageandsettingthevalueofstockVal(aninstancevariablerepresentingthestockvalue)atonetime.
Thisservletisalittletoocomplicatedforoneclass,asitusesservletAPIandHTMLparsingAPIclasses.AbetterdesignwouldseparatetheseresponsibilitiesintodifferentJavaclasses.TheupcomingrecipescreateaJavaBeanwhoseresponsibilityistoparseHTMLforalivestockquote.
Figure26-1showstheoutputoftheservlet'sdoGet()method.
Figure26-1.Theuserentersastocksymbolandsubmitstheform
Figure26-2showstheservlet'sdoPost()methodoutputinaNetscapebrowser.
Figure26-2.Theservletreturnsthelateststockpriceforthesymbol
SeeAlso
Recipe26.3oncreatingaJavaBeanasaweb-pageparser;Recipe26.4andRecipe26.5onusingthebeanwithaservletandaJSP,respectively.
Recipe26.3CreatingaJavaBeanasaWebPageParser
Problem
YouwanttocreateaJavaBeanthatwebcomponentscanusetoparseanHTMLpage.
Solution
UsetheJavaAPIclassesforparsingHTMLfromthejavax.swing.textsubpackages.StoretheJavaBeaninWEB-INF/classesorinaJARplacedinsideWEB-INF/lib.
Discussion
Example26-4isaJavaBeanwhosesolepurposeistoparseawebpageforlivestockquotes.AservletorJSPcanusethisJavaBeanforitsspecialpurpose,andthusavoidtheclutteroftakingontheparsingresponsibilityitself.Allofthecode,includingtheinnerclassrepresentingaParserCallback,isreproducedfromthischapter'searlierrecipes.What'snewisthesetterormutatormethodforthebean'sstocksymbol:setSymbol(Stringsymbol).
Example26-4.AJavaBeanforusewithservletsandJSPs
packagecom.jspservletcookbook;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.net.URL;
importjava.net.MalformedURLException;
importjavax.swing.text.html.HTMLEditorKit.ParserCallback;
importjavax.swing.text.MutableAttributeSet;
importjavax.swing.text.html.parser.ParserDelegator;
publicclassStockPriceBean{
privatestaticfinalStringurlBase="http://finance.yahoo.com/"+
"q?d=t&s=";
privateBufferedReaderwebPageStream=null;
privateURLstockSite=null;
privateParserDelegatorhtmlParser=null;
privateMyParserCallbackcallback=null;
privateStringhtmlText="";
privateStringsymbol="";
privatefloatstockVal=0f;
publicStockPriceBean(){}
//Setterormutatormethodforthestocksymbol
publicvoidsetSymbol(Stringsymbol){
this.symbol=symbol;
}
classMyParserCallbackextendsParserCallback{
//breadcrumbsthatleadustothestockprice
privatebooleanlastTradeFlag=false;
privatebooleanboldFlag=false;
publicMyParserCallback(){
//Resettheenclosingclass'instancevariable
if(stockVal!=0)
stockVal=0f;
}
publicvoidhandleStartTag(javax.swing.text.html.HTML.Tagt,
MutableAttributeSeta,intpos){
if(lastTradeFlag&&(t==javax.swing.text.html.HTML.Tag.B)){
boldFlag=true;
}
}//handleStartTag
publicvoidhandleText(char[]data,intpos){
htmlText=newString(data);
if(htmlText.indexOf("Nosuchtickersymbol.")!=-1){
thrownewIllegalStateException(
"InvalidtickersymbolinhandleText()method.");
}elseif(htmlText.equals("LastTrade:")){
lastTradeFlag=true;
}elseif(boldFlag){
try{
stockVal=newFloat(htmlText).floatValue();
}catch(NumberFormatExceptionne){
try{
//teaseoutanycommasinthenumberusing
//NumberFormat
java.text.NumberFormatnf=java.text.NumberFormat.
getInstance();
Doublef=(Double)nf.parse(htmlText);
stockVal=(float)f.doubleValue();
}catch(java.text.ParseExceptionpe){
thrownewIllegalStateException(
"Theextractedtext"+htmlText+
"cannotbeparsedasanumber!");
}//try
}//try
lastTradeFlag=false;
boldFlag=false;
}//if
}//handleText
}//MyParserCallback
publicfloatgetLatestPrice()throwsIOException,MalformedURLException{
stockSite=newURL(urlBase+symbol);
webPageStream=newBufferedReader(newInputStreamReader(stockSite.
openStream()));
htmlParser=newParserDelegator();
callback=newMyParserCallback();//ParserCallback
synchronized(htmlParser){
htmlParser.parse(webPageStream,callback,true);
}//synchronized
//resetsymbol
symbol="";
returnstockVal;
}//getLatestPrice
}//StockPriceBean
ThisbeanresetsthesymbolinstancevariabletotheemptyStringwhenit'sfinishedfetchingthestockquote.TheMyParserCallbackclassresetsthestockValinstancevariableto0,sothatthepreviouslyattainedstockpricedoesnotlingerbetweendifferentthread'scallstogetLatestPrice().
Nowlet'sseehowaservletandJSPusethebean.
SeeAlso
Recipe26.4onusingthisJavaBeaninaservlet;Recipe26.5onusingthebeaninaJSP.
Recipe26.4UsingtheWebPageParsingJavaBeaninaServlet
Problem
YouwanttousetheJavaBeanforparsingHTMLinaservlet.
Solution
Createaninstanceofthebeanintheappropriateservicemethod(e.g.,doGet()ordoPost())andcallitsmethods.
Discussion
TheJavaBeanhastobeavailabletotheservlet,andthereforestoredinWEB-INF/classes,includingsubdirectoriesthatmatchthebean'spackagename.TheJavaBeancanalsobestoredinaJARinsideofWEB-INF/lib.
SincetheJavaBeaninExample26-5sharestheservlet'spackage(com.jspservletcookbook),theservletclassdoesnothavetoimportthebeanclass.
IftheJavaBeanresidesinadifferentpackageinthewebapplication,thentheservlethastoincludeanimportstatementsuchasthefollowingexample:
importcom.parkerriver.beans.BeanParserServlet;
ThedoGet()methodprovidesanHTMLformforenteringastocksymbol(suchas"intc").ThedoPost()methodthencreatesan
instanceoftheStockPriceBean,callsthebean'ssetSymbol()method,andfinallydisplaysthestockpricebycallingthebean'sgetLatestPrice()method.
Example26-5.AservletusesaspeciallydesignedJavaBeantogetalivestockquote
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassBeanParserServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
//useaPrintWritersendtextdatatotheclient
java.io.PrintWriterout=response.getWriter();
//BeginassemblingtheHTMLcontent
out.println("<html><head>");
out.println("<title>StockPriceFetcher</title></head><body>");
out.println("<h2>Pleasesubmitavalidstocksymbol</h2>");
//makesuremethod="POST"sothattheservletservicemethod
//callsdoPostintheresponsetothisformsubmit
out.println(
"<formmethod=\"POST\"action=\""+request.getContextPath()+
"/stockbean\">");
out.println("<tableborder=\"0\"><tr><tdvalign=\"top\">");
out.println("Stocksymbol:</td><tdvalign=\"top\">");
out.println("<inputtype=\"text\"name=\"symbol\"size=\"10\">");
out.println("</td></tr><tr><tdvalign=\"top\">");
out.println("<inputtype=\"submit\"value=\"SubmitInfo\"></td></tr>");
out.println("</table></form>");
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
Stringsymbol;//thiswillholdthestocksymbol
floatprice=0f;
symbol=request.getParameter("symbol");
booleanisValid=(symbol==null||symbol.length()<1)?
false:true;
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
//useaPrintWritersendtextdatatotheclient
java.io.PrintWriterout=response.getWriter();
//BeginassemblingtheHTMLcontent
out.println("<html><head>");
out.println("<title>Lateststockvalue</title></head><body>");
if(!isValid){
out.println(
"<h2>Sorry,thestocksymbolparameterwaseitherempty"+
"ornull</h2>");
}else{
out.println("<h2>Hereisthelatestvalueof"+symbol+"</h2>");
StockPriceBeanspbean=newStockPriceBean();
spbean.setSymbol(symbol);
price=spbean.getLatestPrice();
out.println((price==0?"Thesymbolisprobablyinvalid.":
""+price));
}//if
out.println("</body></html>");
}//doPost
}//HttpServlet
Theservlet'sHTMLform(generatedbythedoGet()method)andthestockpricedisplay(generatedbydoPost())hasthesamewebbrowserdisplayastheoneshowninFiguresFigure26-1andFigure26-2.
SeeAlso
Recipe26.3oncreatingaJavaBeanasawebpageparser;Recipe26.5onusingawebpageparsingJavaBeaninaJSP.
Recipe26.5UsingtheWebPageParsingJavaBeaninaJSP
Problem
YouwanttouseaJavaBeanandJSPtoharvestinformationfromawebpage.
Solution
Usethejsp:useBeanstandardactiontocreateaninstanceofthebean.
Discussion
ThesameJavaBeanthatpriorrecipescreatedandstoredinthewebapplicationinWEB-INF/classescanbeusedbyaJSP.TheJSPinExample26-6usesjsp:useBeantocreateaninstanceofthebeannamedpriceFetcher.Iftherequestdoesnotcontainasymbolparameter,theJSPdisplaystheHTMLformshowninFigure26-1.
TheJSPusestheJSTLcoretagstogeneratethisconditionalbehavior.Thesetagsincludec:choose,c:when,andc:otherwise.
IftherequesttotheJSPcontainsasymbolparameter,theJSPsetsthepriceFetcher'ssymbolpropertytothevalueofthisrequestparameter.Thiscodeistheequivalentofcallingthebean'ssetSymbol()method;itpassesthenameofthestocksymboltothebeansothatitcangrabalivestockquotefromthewebpage.
Example26-6.AJSPusesjsp:useBeantoemployaweb-harvestingJavaBean
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<jsp:useBeanid="priceFetcher"class=
"com.jspservletcookbook.StockPriceBean"/>
<html>
<head><title>PriceFetch</title></head>
<body>
<c:choose>
<c:whentest="${emptyparam.symbol}">
<h2>Pleasesubmitavalidstocksymbol</h2>
<formmethod="POST"action=
'<c:outvalue="${pageContext.request.contextPath}"/>/priceFetch.jsp'>
<tableborder="0"><tr><tdvalign="top">Stocksymbol:</td>
<tdvalign="top">
<inputtype="text"name="symbol"size="10"></td></tr>
<tr><tdvalign="top">
<inputtype="submit"value="SubmitInfo"></td></tr>
</table></form>
</c:when>
<c:otherwise>
<h2>Hereisthelatestvalueof<c:outvalue="${param.symbol}"/></h2>
<jsp:setPropertyname="priceFetcher"property="symbol"value=
"<%=request.getParameter(\"symbol\")%>"/>
<jsp:getPropertyname="priceFetcher"property="latestPrice"/>
</c:otherwise>
</c:choose>
</body>
</html>
NowthattheJSPhasseededthebeanwiththestocksymbol,thiscodewillcallthebean'sgetLatestPrice()method:
<jsp:getPropertyname="priceFetcher"property="latestPrice"/>
TheJSP'soutputreplacesthejsp:getPropertystandardactionwiththestockprice,aslongasthestocksymbolsenttothebeanwithjsp:setPropertywasvalid.
TheoutputoftheJSPinExample26-6looksjustliketheoutputshowninFiguresFigure26-1andFigure26-2.
SeeAlso
Chapter23ontheJSTL;Recipe26.4onusingawebpageparsingJavaBeaninaservlet.
Chapter27.UsingtheGoogleandAmazonWebAPIs
Introduction
Recipe27.1.GettingSetUpwithGoogle'sWebAPI
Recipe27.2.CreatingaJavaBeantoConnectwithGoogle
Recipe27.3.UsingaServlettoConnectwithGoogle
Recipe27.4.UsingaJSPtoConnectwithGoogle
Recipe27.5.GettingSetUpwithAmazon'sWebServicesAPI
Recipe27.6.CreatingaJavaBeantoConnectwithAmazon
Recipe27.7.UsingaServlettoConnectwithAmazon
Recipe27.8.UsingaJSPtoConnectwithAmazon
Introduction
GoogleandAmazon.comarebothearlyadoptersintheemergingfieldofwebservices.
Googleisagiantwebsearchengineanddirectory.Amazon.comisae-commercewebsitethatbeganasanonlinebookstoreandhassincebranchedoutintonumerousproductssuchassoftwareandelectronics.BothsitesseparatelyoffersoftwaredeveloperswebservicesApplicationProgrammingInterfaces(APIs)thatgiveyoutheabilitytomanageGooglesearchesusingJavaobjectsandaccessAmazon'scomprehensiveproductcatalogswithyourJavacode.
ForusJavadevelopers,webservicesmeansmakingrequestsandreceivingresponsesusingaspecialXMLformat.Inotherwords,youmakearequestusingXMLelementsandattributesintextform,andreceivearesponseinthesameformat.WebservicestypicallyuseanXML-basedprotocolnamedSimpleObjectAccessProtocol(SOAP)totransferinformation.
Inanutshell,SOAPrepresentstheabstractionofanenvelope,thatinturncontainsoptionalheadersandthemessagebody.Themessage,composedofitsouterenvelope,aswellastheheadersandbody,ismadeupofXMLelementsthatareassociatedwithspecifiednamespaces.ThetechnologiesthischapterdescribesuseHTTPtocarrytheseXML-basedSOAPmessages.
IneverreallyunderstoodSOAPmessagesuntilIlookedatsomesamples.Example27-1ispartofaSOAPresponsetoanAmazonWebServiceskeyword-searchrequestusingthequery"LanceArmstrong."
TheresponseisanXMLfilecomposedofaProductInforootelement,whichcontainsoneormoreDetailselements.EachoneoftheseDetailsrepresentsabookfromAmazon'scatalog(IomittedallbutoneoftheDetailselements,justtomakethesampleeasiertoview).Onlyoneofthereturnedbooksisshown.
Example27-1.ASOAPresponsefromAmazonWebServicesbasedonasearchfortheterms"LanceArmstrong"
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEProductInfoPUBLIC"-//Amazon.com//DTDAmazonProductInfo//EN"
"http://xml.amazon.com/schemas/dev-lite.dtd">
<ProductInfoxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation=
"http://xml.amazon.com/schemas/dev-lite.xsd">
<Detailsurl=
"http://www.amazon.com/exec/obidos/ASIN/0399146113/webservices-20?
dev-t=DCJEAVXSDVPUD%26camp=2025%26link_code=xm2">
<Asin>0399146113</Asin>
<ProductName>It'sNotAbouttheBike:MyJourneyBacktoLife
</ProductName>
<Catalog>Book</Catalog>
<Authors>
<Author>LanceArmstrong</Author>
<Author>SallyJenkins</Author>
</Authors>
<ReleaseDate>June,2000</ReleaseDate>
<Manufacturer>PutnamPubGroup</Manufacturer>
<ImageUrlSmall>
http://images.amazon.com/images/P/0399146113.01.THUMBZZZ.jpg
</ImageUrlSmall>
<ImageUrlMedium>
http://images.amazon.com/images/P/0399146113.01.MZZZZZZZ.jpg
</ImageUrlMedium>
<ImageUrlLarge>
http://images.amazon.com/images/P/0399146113.01.LZZZZZZZ.jpg
</ImageUrlLarge>
<ListPrice>$24.95</ListPrice>
<OurPrice>$17.47</OurPrice>
<UsedPrice>$9.99</UsedPrice>
</Details>
</ProductInfo>
ThreeprincipalreasonsforadoptingSOAP-basedwebservicesare:
1. SOAPisstandards-based,soyoucanuseanytechnologythathasdevelopedaSOAPAPIortoolkit,includingJava,.NET,Perl,andPython.Object-orientedtechnologies(likeJava)allowyoutobuildandreadSOAPmessagesusingobjects,insteadofhavingtodealwithrawXML,whichcanmakewebservicesgratifyingtoworkwith.
Webservicesrepresentinteroperabilitybetweentechnologies.AserverthatisusingJ2EEtechnologiessuchasservletsandJSPscaneasilyexchangemessageswithaserverrunning.NET,becausetheyspeakthesamelanguage:SOAPandXML.
SOAPmessagescaneasilybeexchangedbetweenwebserverswithoutrunningafoulofthelimitationsoffirewalls,becausethemessagesaremadeofupXMLtextandcarriedbyHTTP(inaverygeneralway,justlikeanHTMLpage).DevelopersareembracingSOAPasaneasierformofdistributedcomputing:itallowsanobjectresidinginthememoryofoneservertocallmethodsononeormoreobjectsresidingondistantcomputersbyexchangingSOAPmessages.
ArecipeintroductioncannotdojusticetoacomplicatedtopicsuchasSOAP,butthereareplentyofbooksandfreetutorialsonthistopic(seethischapter's"SeeAlso"sectionsforsomesuggestions).
Mostlyinabetastageofdevelopment,theAmazonandGooglewebservicesAPIsallowaJavaprogramtocreateveryusefulandcomplexsystemsthatinteractwithAmazonandGoogle.TheAmazonandGooglewebservicesprogramsaredesignedtofamiliarizedeveloperswiththesenewwaysofhandlingrequestsandresponsestothetwopopularwebdestinations.
Theprogramsgenerallyinvolvecreatingadeveloper'saccountandrecievingakey,ortoken,thatwillaccompanyeachoneofyourrequeststothesesites.ThischapterdescribeshowtogetsetupwithusingAmazonandGooglewebservices,thenshowsyouhowtointegratetheseAPIswithaservletandJSP.
Recipe27.1GettingSetUpwithGoogle'sWebAPI
Problem
YouwanttouseGoogle'sWebAPItomakeJava-enabledsearchesofGoogle'svastwebindex.
Solution
DownloadtheGoogleWebAPIsSDK.CreateaGoogleaccountandgetalicensekeythatallowstheuseofGoogle'sWebAPI.
Discussion
TheGoogleWebAPIsSDKincludesanarchivenamedgoogle.jar.ThisfilecontainstheclassesthatyourprogramwillusetoconnectwithGoogleduringsearches.HerearethespecificstepsyoutaketopreparethewebapplicationforconnectingwithGoogle:
1. DownloadthezippedSDKfromhttp://www.google.com/apis/download.html.Unpackthisfileintoadirectory(namedgoogleapiinBetaVersion3.0oftheGoogleWebAPIs).Thisdirectorycontainsgoogle.jar,alongwithalotofcodesamplesanddocumentation.
CreateaGoogleaccountandgetalicensekey,whichisencodedtextthatlookslike"5W1ABCyzPSyI3rIa5Pt3DtXMatsdzaSGB."YourJavacodeusesthiskeywhenitqueriesGoogle'sindex.Thequerywillfailifitisnotaccompaniedbyavalidkey.
Placethegoogle.jarfileintheWEB-INF/libdirectoryofthewebapplication.
DevelopyourJavaclassesforconnectingwithGoogle,usingthecom.google.soap.searchpackagefromthegoogle.jarfile.
SeeAlso
ThehomefortheGoogleWebAPIs:http://www.google.com/apis/;theGooglewebAPIsSDK:http://www.google.com/apis/download.html.
Recipe27.2CreatingaJavaBeantoConnectwithGoogle
Problem
YouwanttouseGoogle'sWebAPIstomakeJava-enabledsearchestoGoogle'ssite.
Solution
CreateaJavaBeansothatyoucanusethebeaninbothaservletandJSP.
Discussion
ThefirstthingtodoisgetsetupwithaGoogleWebServicesaccount,asdescribedinRecipe27.1.NowcreateaJavaBeanthatwillmakekeywordsearchesofGoogleandreturntheresults.
Example27-2firstimportsthepackagecontainedingoogleapi.jar:com.google.soap.search.Remember,youstoredthatJARfileinWEB-INF/lib.ThismeansthatthewebapplicationcanfindtheJavaclassesinthatpackageandtheGoogleBeaninExample27-2canuseit.
Example27-2.AJavaBeanthatsearchesGoogle'swebdatabase
packagecom.jspservletcookbook;
importcom.google.soap.search.*;
publicclassGoogleBean{
privateGoogleSearchsearch;
privateGoogleSearchResultgoogleRes;
privatefinalstaticStringGOOGLE_KEY=
"5W1BWPyzPSyI3rIa5Pt3DtXMatsniSGB";
privateStringlineSep="\n";
//Settablebeanproperties
privateStringquery;
privatebooleanfilter;
privateintmaxResults;
privateintstartRes;
privatebooleansafeSearch;
privateStringrestrict;
privateStringlangRestrict;
publicGoogleBean(){//No-argumentsconstructorforthebean
query="";
restrict="";
langRestrict="";
}
publicStringstructureResult(GoogleSearchResultres){
//EachGoogleSearchResultElement
GoogleSearchResultElement[]elements=res.getResultElements();
Stringurl="";
Stringresults="Estimatedtotalresultscount:"+
res.getEstimatedTotalResultsCount()+lineSep+lineSep;
for(inti=0;i<elements.length;i++){
url=elements[i].getURL();
results+=("Title:"+elements[i].getTitle()+lineSep+
"URL:<ahref=\""+url+"\">"+url+"</a>"+lineSep+
"Summary:"+elements[i].getSummary()+lineSep+
"Snippet:"+elements[i].getSnippet()+lineSep+lineSep);
}
returnresults;
}
publicStringgetSearchResults()throwsGoogleSearchFault{
search=newGoogleSearch();
search.setKey(GOOGLE_KEY);
search.setFilter(filter);
if(restrict.length()>0)
search.setRestrict(restrict);
search.setQueryString(query);
googleRes=search.doSearch();
returnstructureResult(googleRes);
}
publicvoidsetLineSep(StringlineSep){
this.lineSep=lineSep;
}
publicStringgetLineSep(){
returnlineSep;
}
publicvoidsetQuery(Stringquery){
this.query=query;
}
publicStringgetQuery(){
returnquery;
}
publicvoidsetRestrict(Stringquery){
this.restrict=restrict;
}
publicStringgetRestrict(){
returnrestrict;
}
publicvoidsetLangRestrict(StringlangRestrict){
this.langRestrict=langRestrict;
}
publicStringgetLangRestrict(){
returnlangRestrict;
}
publicvoidsetFilter(booleanfilter){
this.filter=filter;
}
publicbooleangetFilter(){
returnfilter;
}
publicvoidsetSafeSearch(booleansafeSearch){
this.safeSearch=safeSearch;
}
publicbooleangetSafeSearch(){
returnsafeSearch;
}
publicvoidsetMaxResults(intmaxResults){
this.maxResults=maxResults;
}
publicintgetMaxResults(){
returnmaxResults;
}
publicvoidsetStartRes(intstartRes){
this.startRes=startRes;
}
publicintgetStartRes(){
returnstartRes;
}
}//GoogleBean
TheinterestingactioninExample27-2occursinthemethodsgetSearchResults()andstructureResults().
IngetSearchResults(),thecodecreatesaGoogleSearchobject,whichisthencustomizedwithGooglesearchoptionsbeforetheGoogleSearchdoSearch()methodiscalled.TheGoogleSearchobjectusessettermethodstodesignaspecificgoogle.comsearch.Forexample,thesetQueryString()methodprovidestheuser'ssearchterms.TheJavaobjectsthatareusingthebeanprovidesthesearchtermsbycallingthebean'ssetQuery()method.
YoucansetthevariousoptionsforGooglesearchesbycallingtheGoogleSearchsettermethods.Forexample,callingsetFilter(true)filtersoutalltheresultsthatderivefromthesamewebhost.AndyoucanrestrictthesearchtospecificGooglesubsitesbycallingsetRestrict("mac").Seehttp://www.google.com/apis/reference.html.
EverySOAP-relatedsearchofGooglemustcalltheGoogleSearchsetKey()methodwiththeproperlicensekey,orthesearchisrejected.
ThestructureResults()methodformatsthesearchresults.GooglesearchresultsareencapsulatedbyaGoogleSearchResultobject.ThisobjectcontainsanarrayofGoogleSearchResultElementobjects,whichrepresenteachURLthattheGooglesearchhasreturned.
TheGoogleSearchResultgetResultElements()methodreturnstheGoogleSearchResultElementarray.
Thecodetheniteratesthroughthearray.Eachreturnedelement(theGoogleSearchResultElementobject)hasgetteroraccessormethodsthatprovidesinformationabouttheweb-pagesearchresult:
getURL()returnstheURLofthefounditem
getTitle()returnsthetitleofthefoundHTMLpage
getSnippet()returnsasnippet(asmall,possiblyambiguous,pieceoftextfromthewebpage)
getSummary()returnsatextsummaryofthefoundwebpage
ThebeanusesthesemethodstodisplaytheURL,title,snippet,andsummaryofeachwebpagethesearchreturns.Figure27-2showshowtheseresultsaredisplayed.
SeeAlso
ThehomeforGoogleWebService:http://www.google.com/apis/;theGoogleWebAPIsSDK:http://www.google.com/apis/download.html;Recipe27.1onsettingupyourprogrammingenvironmentforusewiththeGoogleWebAPIs.
Recipe27.3UsingaServlettoConnectwithGoogle
Problem
YouwanttoconnecttoGooglewithaservletandinitiateasearch.
Solution
UsetheJavaBeandescribedinRecipe27.2asaGooglesearchutilityclass.
Discussion
TheservletinExample27-3usestheGoogleBeanfromRecipe27.2toinitiategoogle.comsearchesanddisplaytheresults.
TheservletdisplaysanHTMLforminitsdoGet()method.TheclientusesthisformtoinputGooglesearchparameters,andthenPOSTtheformparametersbacktothesameservlet.Finally,theservlet'sdoPost()methodcreatesaninstanceoftheGoogleBeantoinitiatethesearch.Inthiscase,usethedeploymentdescriptortomapanyrequestsoftheform"/googleservlet"toExample27-3.
Example27-3.AservletusesaspecialJavaBeantosearchGoogleanddisplayanyresults
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassGoogleServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head>");
out.println("<title>InitiateaGoogleSearch</title></head><body>");
out.println("<h2>Pleaseenteryoursearchterms</h2>");
//Makesuremethod="POST"sothattheservletservicemethod
//callsdoPostintheresponsetothisformsubmit
out.println(
"<formmethod=\"POST\"action=\""+request.getContextPath()+
"/googleservlet\">");
out.println("<tableborder=\"0\"><tr><tdvalign=\"top\">");
out.println("Searchterms:</td><tdvalign=\"top\">");
out.println("<inputtype=\"text\"name=\"query\"size=\"15\">");
out.println("</td></tr><tr><tdvalign=\"top\">");
out.println(
"RestricttoGooglesub-site...</td><tdvalign=\"top\">");
out.println(
"<selectname=\"restrict\"><option>unclesam</option>"+
"<option>linux</option>option>mac</option><option>bsd</option>"+
"</select>");
out.println("</td></tr><tr><tdvalign=\"top\">");
out.println(
"<inputtype=\"submit\"value=\"SubmitInfo\"></td></tr>");
out.println("</table></form>");
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
Stringquery=request.getParameter("query");
Stringrestrict=request.getParameter("restrict");
booleanisValid=(query==null||query.length()<1)?
false:true;
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head>");
out.println("<title>Googleresults</title></head><body>");
if(!isValid){
out.println(
"<h2>Sorry,thequeryparameterwaseitheremptyornull</h2>");
}else{
out.println("<h2>Hereareyoursearchresults</h2>");
GoogleBeangb=newGoogleBean();
gb.setFilter(true);
//Configureforwebdisplay
gb.setLineSep("<br/>");
if(restrict!=null&&restrict.length()>0)
gb.setRestrict(restrict);
gb.setQuery(query);
try{
out.println(gb.getSearchResults());
}catch(Exceptione){
thrownewServletException(e.getMessage());
}
}//if
out.println("</body></html>");
}//doPost
}//GoogleServlet
UsingtheGoogleBeanclassindoPost()isstraightforward.Thecodesetsafewsearchoptions(suchassetFilter(true)),thencallsthebean'sgetSearchResults()method.ThismethodreturnsaStringofformattedsearchresults,whichtheservlet'sPrintWritersendstothebrowserfordisplay.
Figure27-1showsthesimpleHTMLformdisplayedintheservlet'sdoGet()method.
Figure27-1.EnterkeywordstosearchGooglewithaservlet
The"RestricttoGooglesub-site..."partallowstheusertochooseoneofnone,unclesam,linux,mac,orbsd.Theuserentersthesearchterm
"LanceArmstrong"intheHTMLform'stextfield,thenpressesthe"SubmitInfo"button.Figure27-2showsthesearchresultsdispalyedbytheservlet'sdoPost()method.
TheGoogleWebAPIsdisplayamaximumof10resultspersearch.
Figure27-2.AservletusingtheGoogleWebAPIsdisplayssomesearchresults
SeeAlso
ThehomeforGoogleWebService:http://www.google.com/apis/;theGoogleWebAPIsSDK:http://www.google.com/apis/download.html;Recipe3.1onmappingaservlettoanameinweb.xml;Recipe27.1onsettingupyourprogrammingenvironmentforusewiththeGoogleWebAPIs;Recipe27.4onusingaJSPtoconnectwithGooglewebservices.
Recipe27.4UsingaJSPtoConnectwithGoogle
Problem
YouwanttosearchGoogleusingtheGoogleWebAPIsandaJSP.
Solution
Usethejsp:useBeanstandardactiontogetaccesstotheGoogleBeanfromExample27-2,thenusethisbeaninstancetoconnectwithGoogle'swebtools.
Discussion
TheJSPinExample27-4usestheJSTLcoretagstodetermineiftheuserhassentasearchqueryalongwiththeirrequest.Ifthequeryrequestparameterisempty,thentheJSPdisplaysaform(seeFigure27-1).SeeChapter23fordetailsontheJSTLcoretags.
Iftherequestparameterisfilledbyasearchquery,theJSPusestheGoogleBeantosearchgoogle.comanddisplaytheresults.TheJSPusesthejsp:useBeanstandardactiontocreateaninstanceofthebean,whichisstoredintheWEB-INF/libdirectory.
Example27-4.AJSPusesaJavaBeantosearchgoogle.com
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>SearchGooglefromaJSP</title></head>
<body>
<c:choose>
<c:whentest="${emptyparam.query}">
<h2>Pleaseenteryoursearchterms...</h2>
<%--DisplaytheHTMLform...--%>
<formmethod="POST"action='<c:outvalue=
"${pageContext.request.contextPath}"/>/google.jsp'>
<tableborder="0">
<tr><tdvalign="top">
Searchterms:</td><tdvalign="top">
<inputtype="text"name="query"size="15">
</td></tr>
<tr><tdvalign="top">
RestricttoGooglesub-site...</td><tdvalign="top">
<selectname="restrict">
<optionselected>none</option><option>unclesam</option>
<option>linux</option>
<option>mac</option><option>bsd</option></select>
</td></tr>
<tr><tdvalign="top">
<inputtype="submit"value="SubmitInfo"></td></tr>
</table></form>
<%--EndoftheHTMLform...--%>
</c:when>
<c:otherwise>
<%--CreateaninstanceoftheGoogleBean--%>
<jsp:useBeanid="gBean"class="com.jspservletcookbook.GoogleBean"/>
<h2>Hereareyoursearchresults</h2>
<%--Setthequery,restrict,andlineSeppropertiesoftheGoogleBean--%>
<jsp:setPropertyname="gBean"property="query"param="query"/>
<jsp:setPropertyname="gBean"property="restrict"param="restrict"/>
<jsp:setPropertyname="gBean"property="lineSep"value="<br/><br/>"/>
<%--Nowdisplayanyresultsofthesearch--%>
<jsp:getPropertyname="gBean"property="searchResults"/>
</c:otherwise>
</c:choose>
</body>
</html>
TheJSPusesthejsp:setPropertystandardactiontothebeaninstance'squery,restrict,andlineSepproperties.Thequeryrepresentsthesearchterms;restrictcanhavevaluesofmac,linux,bsd,orunclesam,representingvariousGooglesub-sites,andthelineSeppropertydeterminestheline-separationcharacterstousewhenformattingtheresults(<br/>inthisexample).
Finally,thecodeusesjsp:getPropertytoeffectivelycalltheGoogleBean'sgetSearchResults()method,whichsendsaSOAPmessagetoGoogleandformatstheresponse.
SeeAlso
ThehomeforGoogleWebService:http://www.google.com/apis/;theGooglewebAPIsSDK:http://www.google.com/apis/download.html;Recipe27.1onsettingupyourprogrammingenvironmentforusewiththeGoogleWebAPIs;Recipe27.3onusingaservlettoconnectwithGooglewebservices.
Recipe27.5GettingSetUpwithAmazon'sWebServicesAPI
Problem
YouwanttoconnecttoAmazonWebServices(AWS)withaservletorJSP.
Solution
DownloadtheAmazonWebServicesSDK,acquireanAmazondeveloper'stoken,andcreateaJava-SOAPpackageforinteractingwithAWS.
Discussion
TheprocessforsettingupAWSgoeslikethis:
1. DownloadtheAWSSDKathttp://www.amazon.com/gp/aws/download_sdk.html/002-2688331-0628046.Thiskit.zipfileincludesseveralcodesamplesandwebservicesAPIdocumentationinHTMLformat.
Acquireadeveloper'stokenfrom:http://associates.amazon.com/exec/panama/associates/join/developer/application.html/002-2688331-0628046.SimilartothelicensekeyyouusewithGoogle'sWebAPIs,thefree-of-chargetokencomprisesaseriesofencodedcharactersthatmustaccompanyeachinteractionbetweenyourJavacodeandAWS.
DeveloptheJavaAPIformakingSOAPrequeststoAWS.TheendresultisaJARfilecontainingtheclassesthatyourservletsorJSPsusetomakeSOAPrequests.TherestofthisrecipedescribeshowtogeneratethisJARfile,becauseitisamultistepprocess.
InteractingwithAWSusingSOAPmessagesisoneoptionthatAmazonmakesavailabletodevelopers.AnotheroneinvolvesencodingthewebservicesrequestsinURLs,andtherebymakingAWSrequestsviaHTTP(called"XMLoverHTTP").Recipe27-7showsanexampleofthisURLsearch(theyareusefulfordebuggingyourSOAPapplications).IfyoustoreanXSLTfileontheWeb,AWSusesthisfiletoformattheresponsetoXML-over-HTTPrequests.SeetheSDKdocumentationformoredetails.
SOAPwithApacheAxis
ThecreationofaJava-SOAPAPIforusingAWSbeginswithdownloadinganopensourceSOAPtoolkitnamedApacheAxis(http://ws.apache.org/axis/).HerearethestepsinvolvedincreatingtheAPI:
1. DownloadAxisandextracttheAxisZIPfiletothedirectoryofyourchoice(thiscreatesadirectorynamedaxis-1_1).
Insidetheaxis-1_1/libdirectoryareseveralJARfiles.PlacetheseJARfilesonyourclasspathandthenrunaprogramnamedorg.apache.axis.wsdl.WSDL2JavatogenerateJavasourcefiles.TheseJavasourcefilescomprisetheJavaAPIyouwillusewithAWSwhenyoucompilethefiles.
DownloadtheWebServicesDescriptionLanguage(WSDL)fileassociatedwiththeAmazonWebServices.Atthiswriting,thefilecanbefoundat:http://soap.amazon.com/schemas3/AmazonWebServices.wsdl.
Thefollowingcommandlinegeneratesthecom.amazon.soap.axispackageforyourJavaAPI.ThecommandlinesinthisrecipeworkonbothWindows-andUnix-basedmachines.ThecommandlineisdesignedtorefertotheAmazonWebServices.wsdlfileinthecurrentdirectory.TheWSDL2JavaprogramgeneratesJavaclassesbasedontheXMLelementsdescribedbytheWSDLXMLfile(XML-to-Javaconversion).ThisallowsyoutoworkwithAWSusingonlyJavaobjects,whichisveryniceit'swhyyouareenduringtheinitialpainofcreatingtheseJavaclasses!Breakupthiscommandlineintoseparatelinestomakeitmorereadable,butwhenyouactuallyrunit,thecommandsmustallbecombinedononeline:
java-cp.;lib/axis.jar;lib/commons-discovery.jar;lib/commons-
logging.jar;lib/jaxrpc.jar;lib/saaj.jar;lib/wsdl4j.jar
org.apache.axis.wsdl.WSDL2JavaAmazonWebServices.wsdl--verbose
--packagecom.amazon.soap.axis
ThiscommandlinegeneratesJavasourcefilesinadirectorytreethatmatchesthespecifiedpackagename(com.amazon.soap.axis).Nowyouhavetocompiletheseclasseswiththejavactool,asinthefollowingcommandline(thecurrentdirectorycontainsthecomdirectory).Onceagain,webreakupthissingle-linecommandintoseparatelinesjustforthesakeofreadability(youhavetorunthecommandlineunbrokenbyanynewlinecharacters):
javac-classpath.;lib/axis.jar;lib/commons-discovery.jar;lib/commons-
logging.jar;lib/jaxrpc.jar;lib/saaj.jar;lib/wsdl4j.jar
com/amazon/soap/axis/*.java
NowJARupallthesefiles.Inthesamedirectorycontainingthetop-levelcomdirectory,thiscommandcreatesaJARfilenamedamazonapi.jar,whichisjustanameIcreatedforit:
jarcvfamazonapi.jar./com
Taketheamazonapi.jar(orwhateveryou'venamedtheJARfile)and
placeitinWEB-INF/lib.There'sonemorestepleft.
MakesurethattheJARfilesorlibrariesthatthecom.amazon.soap.axispackagedependsonarealsoavailabletothewebapplication.Theamazonapi.jarfiledependsonthesameAxislibrariesthatyouaddedtotheclasspathinthepriorjavaandjavaccommand-linesequences.YouhavetoaddtheseJARstoWEB-INF/libaswell(unlessyourapplicationservermakesalloftheselibrariesgenerallyavailabletowebapplications).
Okay,nowforthefunpart,whereyourJavacodegetstoexplorebooksandotherstuffatAmazonusingservlets.Yourservletsshouldusethecom.amazon.soap.axispackageforthispurpose.
SeeAlso
TheAWSSDKhttp://www.amazon.com/gp/aws/download_sdk.html/002-2688331-0628046;ApacheAxis:http://ws.apache.org/axis/;theAmazonWebServicesWSDLfile:http://soap.amazon.com/schemas3/AmazonWebServices.wsdl.
Recipe27.6CreatingaJavaBeantoConnectwithAmazon
Problem
YouwanttocreateaJavaBeanasatypeofAmazonsearchutilityclass.
Solution
SetupyourAmazonAPIasdescribedinRecipe27.5,thencodeaJavaBeanthatusesthecom.amazon.soap.axispackagefromthisAPI.
Discussion
TheJavaBeaninExample27-5,namedAmazonBean,importsthecom.amazon.soap.axispackage.Thispackageisstoredinamazonapi.jar,which(generatedbyRecipe27.5).StoretheJARinthewebapplication'sWEB-INF/libdirectoryandtheAmazonBeaninWEB-INF/classes(oralsoinaJARinWEB-INF/lib).
Example27-5connectswithAmazoninitsgetSearchResults()method.TheAmazonBeanformatsanddisplaysthesearchresultsinstructureResults().Thecodecommentsdescribewhat'sgoingonindetail.
Example27-5.AJavaBeanclassthatsearchesAmazon
packagecom.jspservletcookbook;
importjava.net.URL;
importcom.amazon.soap.axis.*;
publicclassAmazonBean{
//Thedeveloper'stoken
privatefinalstaticStringAMAZON_KEY="DCJEAVDSXVPUD";
//NOTE:AWSVersion3uses"http://xml.amazon.com/xml3"
privatefinalstaticStringEND_POINT=
"http://soap.amazon.com/onca/soap";
privatefinalstaticStringAMAZON_TAG="webservices-20";
privateURLendpointUrl;
privateStringlineSep="\n";
privateStringtotalResults;
privateStringkeyword;
privateStringpage;
privateStringtype;
privateStringmode;
publicAmazonBean(){}//no-argumentsconstructorrequiredforabean
//aneasywaytotestthebeanoutsideofaservlet
publicstaticvoidmain(String[]args)throwsException{
AmazonBeanbean=newAmazonBean();
bean.setKeyword("Lance%20Armstrong");
bean.setType("heavy");
bean.setMode("books");
bean.setPage("1");
System.out.println(bean.getSearchResults());
}
//StructurethesearchresultasaString
publicStringstructureResult(ProductInfoinfo){
//AmazonsearchesreturnProductInfoobjects,which
//containsarrayofDetailsobject.ADetailsobject
//representsanindividualsearchresult
Details[]details=info.getDetails();
Stringresults="";
//eachfoundbookincludesanarrayofauthorsinitsDetails
String[]authors=null;
StringusedP=null;//UsedPriceobject
Stringrank=null;//SalesRankobject
//foreachreturnedsearchitem...
for(inti=0;i<details.length;i++){
if(mode!=null&&mode.equals("books")){
authors=details[i].getAuthors();}
//Includetheproductname
results+=
"<strong>"+(i+1)+".Productname:</strong>"+
details[i].getProductName()+lineSep;
//Iftheyarebooksincludeeachauthor'sname
if(mode!=null&&mode.equals("books")){
for(intj=0;j<authors.length;j++){
results+="Authorname"+(j+1)+":"+authors[j]+
lineSep;
}//for
}//if
usedP=details[i].getUsedPrice();//gettheusedprice
rank=details[i].getSalesRank();//getthesalesrank
results+="Salesrank:"+(rank==null?"N/A":rank)+
lineSep+"Listprice:"+details[i].getListPrice()+lineSep+
"Ourprice:"+details[i].getOurPrice()+lineSep+
"Usedprice:"+(usedP==null?"N/A":usedP)+lineSep+
lineSep;
}
returnresults;
}//structureResult
//ConnectwithAmazonWebServicesthencallstructureResult()
publicStringgetSearchResults()throwsException{
endpointUrl=newURL(END_POINT);
AmazonSearchServicewebService=newAmazonSearchServiceLocator();
//ConnecttotheAWSendpoint
AmazonSearchPortport=webService.getAmazonSearchPort(endpointUrl);
KeywordRequestrequest=getKeywordRequest();
//Returnresultsofthesearch
ProductInfoprodInfo=port.keywordSearchRequest(request);
//SettotalResultswithanyprovidedresultstotal
setTotalResults(prodInfo.getTotalResults());
//Makesurethebook-searchresultsarestructuredanddisplayed
returnstructureResult(prodInfo);
}//getSearchResults
//Setterandgettermethods...
publicvoidsetLineSep(StringlineSep){
this.lineSep=lineSep;
}
publicStringgetLineSep(){
returnlineSep;
}
//AKeywordRequestobjectinitializedwithsearchterms,themode,the
//numberofpagestobereturned,thetype('lite'or'heavy'),andthe
//developer'stoken.
publicKeywordRequestgetKeywordRequest(){
KeywordRequestrequest=newKeywordRequest();
request.setKeyword(keyword);//thesearchterms
request.setMode(mode);//themode,asin'books'
request.setPage(page);//thenumberofpagestoreturn
request.setType(type);//thetype,'lite'or'heavy'
request.setDevtag(AMAZON_KEY);//developer'stoken
request.setTag(AMAZON_TAG);//thetag,'webservices-20'
returnrequest;
}
publicvoidsetKeyword(Stringkeyword){
this.keyword=keyword;
}
publicStringgetKeyword(){
returnkeyword;
}
publicvoidsetMode(Stringmode){
this.mode=mode;
}
publicStringgetMode(){
returnmode;
}
publicvoidsetPage(Stringpage){
this.page=page;
}
publicStringgetPage(){
returnpage;
}
publicvoidsetType(Stringtype){
this.type=type;
}
publicStringgetType(){
returntype;
}
publicvoidsetTotalResults(Stringresults){
totalResults=results;
}
publicStringgetTotalResults(){
returntotalResults;
}
}//AmazonBean
Thebeanhasamain()methodthatallowsyoutotestthebeanfromthecommandline.Hereiscodefromthatmethodthatcreatesabeaninstance,searchesforabookusingthesearchterms"LanceArmstrong,"anddisplayssomeresults:
AmazonBeanbean=newAmazonBean();
bean.setKeyword("Lance%20Armstrong");
bean.setType("heavy");
bean.setMode("books");
bean.setPage("1");
System.out.println(bean.getSearchResults());
Torunthebeanfromacommandline,makesureincludeallofthenecessaryAxis-relatedlibrariesonyourclasspath(seeRecipe27.5).Thefollowingcommandlinerunsthebeantotestit.Notethatthiscommandlineincludestheamazonapi.jarfilegeneratedbyRecipe27.5:
java-cp.;jaxrpc.jar;axis.jar;amazonapi.jar;commons-logging.jar;commons-discovery.
jar;saaj.jarcom.jspservletcookbook.AmazonBean
Ifyousetthetypeoptiontoheavy(asopposedtolite),thenthesearchreturnsthebook'ssalesrankatAmazon.TheliteSOAPresponsesdonotincludeavalueforsalesrank.
SeeAlso
TheAWSSDKhttp://www.amazon.com/gp/aws/download_sdk.html/002-2688331-0628046;Recipe27.7onusingaservletandaJavaBeantoconnectwithAWS.
Recipe27.7UsingaServlettoConnectwithAmazon
Problem
YouwanttoconnectwithAWSusingaservlet.
Solution
UseaspeciallydesignedJavaBeantopeformtheAWS-relatedtasks.
Discussion
Example27-6usesthesamedesignthattheGooglerecipesused,soyoushouldfindthisservletcodeveryfamiliarifyouhaveworkedthroughthoseexamplesbefore.TheservletgeneratesanHTMLforminresponsetoaGETHTTPrequest,whichsendstheAmazonsearchtermsbacktothesameservlet.TheinterestingactiontakesplaceinthedoPost()method,wheretheservletusesanAmazonBeanclass(fromRecipe27.6)toconnectwithAWSanddisplayanysearchresults.
Example27-6.AservletusesaJavaBeantoconnectwithAWS
packagecom.jspservletcookbook;
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassAmazonServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
//settheMIMEtypeoftheresponse,"text/html"
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
//BeginassemblingtheHTMLcontent
out.println("<html><head>");
out.println(
"<title>InitiateanAmazonBookSearch</title></head><body>");
out.println("<h2>PleaseenteryourAmazonsearchterms</h2>");
//DisplayanHTMLformthatsendstherequestbacktothis
//'/amazonservlet'whichwillcausethecallingofdoPost()
//makesuremethod="POST"sothattheservletservicemethod
//callsdoPostintheresponsetothisformsubmit
out.println(
"<formmethod=\"POST\"action=\""+request.getContextPath()+
"/amazonservlet\">");
out.println("<tableborder=\"0\"><tr><tdvalign=\"top\">");
out.println("Searchterms:</td><tdvalign=\"top\">");
out.println("<inputtype=\"text\"name=\"query\"size=\"15\">");
out.println("</td></tr>");
out.println("<tr><tdvalign=\"top\">");
out.println(
"<inputtype=\"submit\"value=\"SubmitInfo\"></td></tr>");
out.println("</table></form>");
out.println("</body></html>");
}//doGet
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,java.io.IOException{
Stringquery=request.getParameter("query");
booleanisValid=(query==null||query.length()<1)?
false:true;
response.setContentType("text/html");
java.io.PrintWriterout=response.getWriter();
out.println("<html><head>");
out.println("<title>Amazonbookresults</title></head><body>");
if(!isValid){
out.println(
"<h2>Sorry,thequeryparameterwaseitheremptyornull</h2>");
}else{
AmazonBeanamBean=newAmazonBean();
amBean.setKeyword(query);
amBean.setType("lite");
amBean.setMode("books");
amBean.setPage("1");
amBean.setLineSep("<br/>");
out.println("<h2>Hereareyoursearchresults</h2>");
try{
out.println(amBean.getSearchResults());
}catch(Exceptione){
out.println(
"Thesearchtermseitherreturnedzeroresults"+
"orwereinvalid.");
}
}
out.println("</body></html>");
}//doPost
}//AmazonServlet
Tokeepthecodesimple,limitthekeywordsearchtobooks.AWSoffersacomprehensivemethodofsearchingitsseveralcatalogs,however,withtheAPInotlimitedtokeywordsearchesofbooks.Forexample,theproductmodesincludeDVD,electronics,music,hardware,software,andtoys.Youcanalsoinitiateseveraldifferentsearchtypes(inadditiontokeywords),suchasAmazonStandardItemNumber(ASIN)searches.
Figure27-3showsthereturnvalueoftheservlet'sdoGet()method.
Figure27-3.Aservlet'sHTMLformacceptsAmazonsearchterms
Figure27-4showspartsoftheservlet'sdisplayedresultsthatarehandledbytheservlet'sdoPost()method.
Figure27-4.TheresultsofanAmazonbooksearch
OnceyouhavedownloadedandunpackedtheAWSSDK,thesoftwaredocumentationislocatedat:AmazonWebServices/APIGuide/index.html.
TohelpdebugyourAWSsearchesandservlets,youcaninitiateanAWSsearchusingaUniformResourceLocator(URL)inyourbrowser.ThefollowingURLinitiatesakeywordseachforabookusingtheterms"BritishEmpire."
http://xml.amazon.com/onca/xml?v=1.0&t=webservices-20&
dev-t=DCJEAVXSDVPUD&KeywordSearch=British%20Empire&mode=books&
type=lite&page=1&f=xml
AnrequestforthisURLreturnsanXMLfilethatlookssimilartoExample27-1.Thesalesrankreads"N/A"becausethesearchoptiontype=litereturnsanullvalueforthisranking.Usetype=heavytogetavaluefortheAmazonsalesrank.
SeeAlso
TheAWSSDKhttp://www.amazon.com/gp/aws/download_sdk.html/002-2688331-0628046;WebServicesEssentials(O'Reilly);Recipe3.1onmappingaservlettoanameinweb.xml;Recipe27.8onusingaJSPandaJavaBeantoconnectwithAWS.
Recipe27.8UsingaJSPtoConnectwithAmazon
Problem
YouwanttoconnectwithAWSusingaJSP.
Solution
Usethejsp:useBeanstandardactiontocreateaninstanceoftheAmazonBeanfromRecipe27.6.UsethisinstancetomanagetheAWSsearchandresults.
Discussion
ThisrecipeusesthesamestrategyastheJSPinRecipe27.4:createaJavaBeaninstancethathandlestheAWSsearchanddisplaysthesearchresults.Thejsp:useBeanstandardactioncreatesaninstanceofcom.jspservletcookbook.AmazonBean,whichislocatedinWEB-INF/classes.
Thenthecodeusesjsp:setPropertytosetsomesearchoptions,beforetheJSPusesjsp:getPropertytolaunchtheseach.Example27-7usestheJSTLtagc:catchtocatchanyexceptionsthrownbytheAmazonBean'sgetSearchResults()method.ThevariableexceptisofthetypeThrowable,anditserrormessageisdisplayedbythec:outtagifthesearchqueryisinvalid.TheJSPinExample27-7displaystheHTMLformandsearchresultsshowninFiguresFigure27-3andFigure27-4.
Thisjsp:getPropertycodeistheequivalentofcallingtheAmazonBean'sgetSearchResults()method,whichreturnsaStringofformattedsearchresults.
Example27-7.AJSPlaunchesanAWSbooksearch
<%@tagliburi="http://java.sun.com/jstl/core"prefix="c"%>
<html>
<head><title>SearchAmazon.comforaBook</title></head>
<body>
<c:choose>
<c:whentest="${emptyparam.keyword}">
<h2>PleaseenteryourAmazonsearchterms...</h2>
<%--DisplaytheHTMLform...--%>
<formmethod="POST"action=
'<c:outvalue="${pageContext.request.contextPath}"/>/amazon.jsp'>
<%--formandtabletags...--%>
<tableborder="0"><tr><tdvalign="top">
Searchterms:</td><tdvalign="top">
<inputtype="text"name="keyword"size="15">
</td></tr><tr><tdvalign="top">
<tr><tdvalign="top">
<inputtype="submit"value="SubmitInfo"></td></tr>
</table></form>
</body></html>
</c:when>
<c:otherwise>
<jsp:useBeanid="aBean"class="com.jspservletcookbook.AmazonBean"/>
<jsp:setPropertyname="aBean"property="keyword"param="keyword"/>
<jsp:setPropertyname="aBean"property="mode"value="books"/>
<jsp:setPropertyname="aBean"property="page"value="1"/>
<jsp:setPropertyname="aBean"property="type"value="lite"/>
<jsp:setPropertyname="aBean"property="lineSep"value="<br/>"/>
<h2>Hereareyoursearchresults</h2>
<c:catchvar="excep">
<%--Nowdisplayanyresultsofthesearch--%>
<jsp:getPropertyname="aBean"property="searchResults"/>
</c:catch>
<%--Printanyerrormessages,suchas'BadRequest'ifthesearch
termsaremeaningless--%>
<c:outvalue="${excep.message}"/>
</c:choose>
</body>
</html>
SeeAlso
TheAWSSDK:http://www.amazon.com/gp/aws/download_sdk.html/002-2688331-0628046;WebServicesEssentials(O'Reilly);Recipe27.7onusingaservletandaJavaBeantoconnectwithAWS;Chapter23on
usingtheJSTL.
Colophon
Ourlookistheresultofreadercomments,ourownexperimentation,andfeedbackfromdistributionchannels.Distinctivecoverscomplementourdistinctiveapproachtotechnicaltopics,breathingpersonalityandlifeintopotentiallydrysubjects.
TheanimalonthecoverofJavaServletandJSPCookbookisafennecfox(Fennecuszerda),alsoknownasthedesertfox.FennesfoxesliveinaridsandyregionsofnorthernAfrica,theSahara,theSinaiPeninsulaandArabiaandareoneofthetiniestmembersofthecaninefamily(eightinchesatthetallestandusuallylessthanafootlong).Theirrelativelyhugeearsandbeadyblackeyesgivethemadistinctiveappearance.Thefennecfox'sbushytailischaracteristicofmostfoxes,andathickcreamycoatcamouflagesthemintheirsandyhabitat.
Fennecfoxesliveinburrowsandarenocturnalhunters,eatingplants,smallrodents,birdsandtheireggs,lizards,andinsects.Theirhearingissoacutethattheycanheareventhesmallestofpreywalkingacrossdesertsand.Thesefoxesoftenstalktheirpreyandpounceuponit;theirverticalleapistwofeethighandtheycanjumpfourfeethorizontallyfromastandingposition,astoundingfeatsforananimalofsuchsmallstature.Theyarerapidandprolificdiggers,knownfor"disappearing"intosandwhileappearingtostandstill.Somereportsnotethatthisspeciescandiga20-foot-longtunnelinonenight!
Thefennecfoxisnotlistedasendangered,butisnowconsideredrareinsomeareaswhereitwasoncecommon.Theyhavebeenhuntedextensivelyandaresometimestakenfromthewildforthepettrade.
PhilipDanglerwastheproductioneditorandcopyeditorforJavaServletandJSPCookbook.SarahShermanandMattHutchinsonweretheproofreaders.RegAubryandMaryAnneWeeksMayoprovidedqualitycontrol.EllenTroutmanZaigwrotetheindex.
EmmaColbydesignedthecoverofthisbook,basedonaseriesdesignbyEdieFreedman.Thecoverimageisa19th-centuryengravingfromAnimateCreations,VolumeOne.EmmaColbyproducedthecoverlayout
withQuarkXPress4.1usingAdobe'sITCGaramondfont.
MelanieWangdesignedtheinteriorlayout,basedonaseriesdesignbyDavidFutato.ThisbookwasconvertedJulieHawkstoFrameMaker5.5.6withaformatconversiontoolcreatedbyErikRay,JasonMcIntosh,NeilWalls,andMikeSierrathatusesPerlandXMLtechnologies.ThetextfontisLinotypeBirka,theheadingfontisAdobeMyriadCondensed,andthecodefontisLucasFont'sTheSansMonoCondensed.TheillustrationsthatappearinthebookwereproducedbyRobertRomanoandJessamynReadusingMacromediaFreeHand9andAdobePhotoshop6.ThetipandwarningiconsweredrawnbyChristopherBing.ThiscolophonwaswrittenbyPhilipDangler.
TheonlineeditionofthisbookwascreatedbytheSafariproductiongroup(JohnChodacki,BeckiMaisch,andMadeleineNewell)usingasetofFrame-to-XMLconversionandcleanuptoolswrittenandmaintainedbyErikRay,BennSalter,JohnChodacki,andJeffLiggett.
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
${}ELexpressiondelimitersdereferencingvariableandpropertyvaluesencapsulatingfunctioncallwithin%inconversionpatterns<!---->,inTomcatserver.xmlfilecomments<%%>,inJSPscriptlets<%----%>inJSPcomments<%@syntax,JSPdirectives2nd*(asterisk)**patterninAntelements,forzeroormoredirectories2ndwildcardcharacterinURLpatterns.(dot)inattributenamesspecifyingcurrentdirectory.(dot)operator.jspfiles.jspxfiles2nd3rd.swffileextension2nd/(forwardslash)/*inURLpatternsforcontrollerservlet2ndforinvokerservletoverridenbycontrollerservletinURLpatterns2ndexcludingfromextensionmapping401UnauthorizedHTTPstatuscode403ForbiddenHTTPstatuscode404NotFoundHTTPstatuscode500InternalServerErrorHTTPstatuscode
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
abort()(LoginModule)actionsinJSPscreatedasXMLfilesactivation.jararchiveActiveXcontrol,FlashfileembeddedinJSPbyInternetExploreraddCookie()(HttpServletResponse)addresses,email2ndAdministrationconsole(WebLogic)configuringJNDIresourceviewingJNDItreeAdobeSystem'sSVGViewerapplicationaliasestoservlets,creatinginweb.xmlfilealready.deployedproperty(Ant,build.xmlfile)AmazonWebServicesconnectingtowithaJSPconnectingtowithaservletcreatingJavaBeantoconnectwithsettingupSOAPresponsetokeywordsearchrequestAnttoolbuild.xmlfilecompilingandcreatingWARfileswithcompilingservletclassescompilingservletwithbuildfilecreatingJARfilesdeployingservletonWebLogicServer7.0deployingsingleservletonTomcatdeployingwebapplicationonTomcatbuild.propertiesfile(example)build.xmlfile(example)stepsinprocessdeployingwebapplicationonWebLogicServer7.0global.propertiesfileobtainingandsettingupdownloadingbinaryorsourcedistributionJAXP-compliantXMLparseronlinemanualforstartingTomcatapplicationwithstoppingTomcatapplicationwithtargets,usingbuild.xmlfile,executingexecutingseveraltargetsinspecifiedsequenceTomcatJARfiles,includinginAntclasspathWARfiles,creatingANT_HOMEenvironmentvariableantcallelementantcalltaskApacheAnt[SeeAnttool]Xerces2XMLparserApacheJakartaProjectlog4jdistribution,downloadingfromreferenceimplementation(RI)fortheJSTL
Standard1.0taglibApacheSoftwareFoundation,Log4jlibraryApacheSoftwareLicenseappBasedirectory(Tomcat,server.xmlfile)appendersaddingtorootloggerConsoleAppenderinheritanceoflayoutspecificationrollingfileappenderusingapatternwithAppleComputer'sQuickTimemoviesapplettags(HTML)appletsembeddinginJSPswithHTMLConvertertoolembeddinginJSPswithjsp:pluginexample(SunMicrosystems)applicationeventlistenersapplicationimplicitobject2ndapplicationname(webapplications)applicationscope2ndbindinganobjecttoapplicationserversBEAWebLogic,recipesinthisbookforapplicationScopeJSTLimplicitobjectArithmeticExceptionclassarrayofcookies2ndarraysGoogleSearchResultElementarrayiteratingoverwithc:forEachtagofSortedMaps,iteratingoverattachments,emailaddingtoanemailinaservlethandlingforemailreceivedinaservletattributedirective2ndattributeAdded()(HttpSessionAttributeListener)attributeRemoved()(HttpSessionAttributeListener)attributeReplaced()(HttpSessionAttributeListener)attributescookiescustomloggingtagdefinitionofJSPscopedattribute,settingtovalueofformpapameterobject,namingconventionforServletContext,settinginJSPsServletContext,settinginservletsobjectthatservletbindstoServletContextservletthatbindsobjecttoServletContextattributionforuseofcodeexamplesaudiofilesembeddinginJSPssendingasMP3filesauth-constraintelement(web.xml)rolesinauth-methodelement(web.xml)form-basedauthentication
valuesforauthentication2ndauthorizationvs.BASICauthentication,usewithwebapplicationsonTomcatcreatingusernamesandpasswordswithTomcatform-basedloggingoutuserJAASconfigurationfile,creatingJAAS,usinginaJSPJAAS,usinginaservletLoginModule,creatingwithJAASSSL,settinguponTomcatauthorization[SeealsoJAAS]authenticationvs.availabletask(Ant,build.xmlfile)
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
backgroundsoundtrack,embeddinginaJSPBase64content-encodingmechanismbasedirattributeAntjartaskAntprojectelementBASICauthenticationform-basedauthentication,usingwithusingwithwebapplicationsonTomcatweb.xmlelementsforinitiationofBasicConfiguratorclassbatchfile,forprecompilingJSPswithTomcatBEAWebLogic[SeeWebLogic]binarydataPDFfile,sendingaswordprocessingfile,sendingasXMLfile,sendingasbindingobjectslisteningforbindingorunbindingofsessionobjectsSessionobject,toWebLogicJNDIimplementationtotheServletContextwithaJSPwithaservletblockingfiltersIPaddresses,blockingrequestsfromrequests,optionallyblockingbodytags(HTML)BodyPartclass2nd3rdBodyTagSupportclass2ndboundarypatternseparatingfilesinHTTPuploadrequestsbrowserwindows,creatingwithJavaScriptinaJSPinaservletbrowserscookiessupportedbydetectingMIMEtypeforembeddedMP3fileandactivatinghelperapplicationtoplaymusicdisplayingXMLfilesinreadableformatembeddingFlashfileinaJSPJavaScriptinviewerapplicationsforSVGfilesBufferedInputStreamclassbuilddirectoryinclusionofnesteddirectoriesinWARfilewithAntwartaskbuildfiles(Ant)command-linesequenceforexecutingcompilingservletwithdeployingwebapplication(example)editedtodeployonWebLogic7.0executingseveraltargetsinspecifiedsequencefunctionsofimportingbuild.propertiesfileintoJSPparsing,usingJSTLXMLtagsnamesotherthanbuild.xml
TomcatManagerapplication,usingfromtransformingintoHTML,usingXSLstylesheetwl.propertiesforWebLogicAntfilebuild.propertiesfile(Ant)deployingwebapplicationonWebLogicServer7.0build.xmlfile[Seebuildfiles]Builder(WebLogic)
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
Clanguage,printffunctionc:choosetagc:forEachtag2ndinterationsperformedbyiteratingovermapvaluesiteratingthroughaMap'sstoredrequestheadersc:iftagtestingexpressionsforconditionalcodeexecutionuseinaJSP(example)c:importtagimportingAntbuildfileintoJSPincludingJavaScriptmoduleinaJSPJavaScriptmodule,importingintoaJSPusebyJSPtoaccessforbiddenresourcec:otherwisetagc:outtag2nd3rddisplayingaJavaBean'spropertiesdisplayingforminputviaaJavaBeandisplayingindividualparametervaluesescapedcharactersexceptioninformation,displayingforJSPpassingvalueofrequest_uriattributetosummaryoffunctionsuseinaJSP(example)c:paramtags,includingparametervaluesinJSPc:settagbindinganobjecttoapplicationscopesettingvariabletosessionscopesummaryoffunctionsc:whentagCallableStatementclassexecuteUpdate()servletusingtocallstoredprocedureCallbackHandlerclass2nd3rdcallbacksclassforsiftingthroughwebpagesdefinitionofParserDelegator,usingwithcasesensitivityurlpatterninservlet-mappingelementsusernamesandpasswordsintomcat-users.xmlfilecastingrequestparametersServletRequesttypetoHttpServletRequestCauchoResin(servletengine)cbck:log(customJSPtag)2ndCDATAsectionsinXMLfiles,usingtopasswell-formedtestCGI(CommonGatewayInterface)characterentitycodes2ndescapedcharactersinc:outtaglistingofCheckEmailfunction,JavaScript
classesJavaServerPageimplementationclassservlet2ndservlet-classelementinweb.xmlclassesdirectory2ndlog4j.propertiesfilespecifyingclasseswithAntwartaskTLDsandWebLogic7.0server,pastingservletclassintoclasseselement(Ant)classictaghandlerscreatingforacustomactioncreatingJSP1.2TLDforcreatingJSP2.0TLDforclasspathelement(Ant)nestedinsidethejavactaskCLASSPATHenvironmentvariable,precompilingJSPsandclasspathsAntclasspaththatincludesTomcatJARfilesemail-relatedclasses,placingoninbuild.xmlfile,forJARfilesinTomcatdirectoriesuser,representedbyCLASSPATHenvironmentvariableWLCLASSPATHenvironmentvariableclientauthentication[Seeauthentication]clientrequestscountingforwebapplicationexaminingHTTPrequestheadersinaJSPexaminingHTTPrequestheadersinaservletfilter,usingtoalterrequestheadersrefreshingaJSPautomaticallyrefreshingaservletautomaticallyclientstateClockclass(exampleapplet)referenceto,embeddedbyJSPclose()InitialContextclassPrintWriterclassclosingdatabaseconnections2ndcodeexamplesinthisbook,useofCollectionsclass,synchronizedMap()com.oreilly.servletlibraryclassesforfileuploadsLocaleNegotiatorclassMultipartFilterclasscom.oreilly.servlet.multipartpackagecommentattribute(cookies)commentsJSPuncommentingConnectorelementinTomcatserver.xmlcommercialservletenginescommit()Connectionclass2ndLoginModuleclassCommonGatewayInterface(CGI)compilingservlets2nd[SeealsoprecompilingJSPs]Anttool,using
PATHenvironmentvariableforjavacwithAntbuildfileconfigure()(BasicConfigurator)configure()(PropertyConfigurator)specifyingnameoflog4j.propertiesfileConnectionclasscommit()2ndgetMetaData()getTransactionIsolation()listingofisolationlevelsrollback()2ndsetAutoCommit()connections,databasecreatingconnectionpoolwithWebLogicConsoleDataSourceasfactoryforopeningandclosingservletusingWebLogicconnectionpoolConnectorelement(server.xml)ConsoleAppenderclasscontainer-managedsecuritycontent[Seealsodynamicallyincludingcontent;staticcontent]non-HTML,sendingaudiofilesPDFfilesviewinginternalresourcesinaservletwordprocessingfilesXMLfilescontenttypesemail2ndMultipartmultipart/form-dataContent-Dispositionheader2ndContent-LengthheaderContent-Typeheaderapplication/mswordMIMEtypescontentTypeattribute(jspdirective.pageelement)contextdefault,forservletsincludingJSPfile,importingcontentfromoutsideContextelement(Tomcatserver.xmlfile)2ndcontextpathforwebapplicationpathattributeofContextelement(Tomcat)context-paramelement(web.xml)cookieage,valuesfordataSourceparameterthatconnectswithadatabaseinternationalizationresourcesJSPthatopenspop-upwindowlocalizationcontext,setting2ndprovidingpathforanincludedfileinaJSPcontext-relativepathcontextDestroyed()(ServletContextListener)contextInitialized(ServletContextListener)ContextObjectclass(example)controllerservlet
exclusiveaccesstocertainservlets,settingupmappingallrequeststowhilepreservingallservletmappingsconversionofaJSPintoaservletconversionpatterns,layoutofloggedmessagesconversionspecifiersinpatternlanguageCookieclassgetName()andgetValue()2ndgetPath()getterandsettermethodsforattributessetMaxAge()2ndargumentvalueofzerosetValue()cookieimplicitobject(JSTL)2ndCookierequestheadercookies2ndaccessingwithELdefinitionofdeletionbyusersdisabledbyusersname/valuepairoptionalattribute/valuepairsoverwritingorremovingexistingcookiesreadingvalueswithaJSPreadingvalueswithaservletsessiontracking,useindisabledcookiessettingwithaJSPsettingwithaservletstoringrequestcookiesinanarraycopytask(Ant)Copyrightservlet(example)CoreJ2EEBlueprintswebpageCorel'sSVGViewercos.jarfilecountrycodes(ISO)2ndcreate-jartarget(Ant)create-wartarget(Ant,build.xmlfile)CreateWindowfunction,JavaScriptcreatingnewbrowserwindowinaservletcreationtimeforsessionstrackingwithJSPstrackingwithservletscurrencies,formattingforlocalesinaJSPinaservletcustomactions2nd[Seealsocustomtags]JSPusingtoaccesslog4jcustomtags2nd3rdassociatedwithatagfile,usingcbck:logtaglogginglevelconfigurationfile,includingyourowncreatingclassictaghandlerforcreatingJSP1.2TLDforclassictaghandlercreatingJSP2.0TLDforclassictaghandlercreatingTLDforasimpletaghandler
functioncallsembeddedintemplatetexthandlingexceptionsincustomtagclassJSPtagfile,creatinglistenerclass,addingtotaglibrarypackagingataglibraryinawebapplicationpackagingJSPtagfileinaJARpackagingtaglibraryinaJARfilesimpletaghandler,creatingsimpletaghandler,usinginaJSPtagfile,packaginginwebapplicationtagthatuseslog4jTLDforcustomloggertagusinginaJSP
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
DatabaseMetaDatainterfacedatabasesaccessingfromservletwithoutDataSourceconfigurationcallingstoredprocedurefromaJSPconfiguringDataSourceinTomcatconvertingResultSettoResultobjectcreatingDataSourceonWebLogicDataSource,usinginservletwithTomcatexecutingseveralSQLstatementsinonetransactioninteractingwithbyconfiguringDataSourceinweb.xmlJNDIlookup,usingtoaccessaWebLogicDataSourceJSTLtagsthatinteractwithResultSetinformation,findingoutstoredprocedure,callingfromaservlettransactions,usingwithJSPsWebLogicDataSource,usinginaJSPDataHandlerclassDataSourceconfigurationinweb.xmlconfiguringforservletinTomcatconfiguringinweb.xmlforSQLJSTLtagscreatingDataSourceobjectonWebLogicconfiguration,stepsinexplicitlysettingforJSTLSQLtagsinaJSPgetConnection()2ndJNDI,accessingwithusinginservletwithTomcatWebLogicDataSource,usinginaJSPDataSourceLoginModule2ndDateclass,getTime()DateFormatclass2ndformat()getDateTimeInstance()datesandtimescreationandlast-accessedtimeforsessionstrackingwithJSPstrackingwithservletsexpirationforcookiesformattingdatesaccordingtorequestlocaleinaJSPinaservletformattingwithJSTLtagscurrentdateinSwissandU.S.stylefmt:formatDatetag,attributesofJSPthatdisplayscurrentlog4jdateformatterofloggingactivitydateStyleandtimeStyleattributes(fmt:formatDate)Davidson,JamesDuncanDEBUGlevellogging2ndinrootloggerdeclarativesecurity
defaultattribute(Antprojectelement)DefaultFileRenamePolicyclassfile-uploadingJavaBean,useindeletingacookiedependsattribute(Anttargetelements)deploy-applicationtarget(Ant,build.xmlfile)editedtodeployonWebLogic7.0deploy-servlettarget(Ant,build.xmlfile)2ndDeployerutility(WebLogic)deployingservletsandJSPsdeployingaspartofTomcat'sContextelementinserver.xmlfileindividualJSP,deployingonTomcatindividualJSP,deployingonWebLogicindividualservlet,deployingonTomcatAnttool,usingstepsinprocessindividualservlet,deployingonWebLogicServer7.0Antfile,usingeditingweb.xmlfiletoregisterservletredeployingwebapplicationwebapplication,deployingonTomcatAntbuildfile,usingwebapplication,deployingonWebLogicusingAnttoolusingWebLogicAdministrationConsoleusingWebLogicBuilderusingweblogic.Deployercommand-lineutilitydeploymentdescriptors[Seealsoweb.xmlfile]creatingforservletAPI2.3servletAPI2.4web.xmlfilecontentsEJBvendor-specific(weblogic-ejb-jar.xml)J2EE,namespaceofopeningandeditinginWebLogicBuildersecurity-relatedelementsinversionsotherthanservletv2.4storageinWEB-INFdirectorytaglibelementweb.xmlfileinWEB-INFdirectorydescriptionattribute(Anttargetelements)destfileattributeAntjartaskAntwartaskdigitalcertificate,creatingforTomcatserverdirattributesAntclasseselementAntfilesetelementsdirectives,JSPinwell-formedXMLfileXMLequivalentsfordirectories**patterninAntelements(zeroormoredirectories)2ndlocal,savingfileuploadstoURLsthatspecifyadirectoryonlydirectorystructureofwebapplications
forapplicationdeployedbyAnttoolexampleofexplodeddirectoryformatJSPfilesindirtyreaddispatcherelements(web.xml)2nddisplayMessage()AttachBeanclass(example)EmailBeanclass(example)HeaderAccessorclass(example)MailAccessorclass(example)distributedcomputing,SOAPaseasierformofdoCatch()(TryCatchFinally)docBaseattribute(Contextelement,Tomcat)DocumentTypeDefinition(DTD)inJSP1.2TLDfileJSP1.2orderforelementsinweb.xml(servlet2.3API)XMLSchemavs.doEndTag()2nddoFilter()blockingrequestscastingrequestparameterchangingservletresponsefilterusingHttpServletResponseWrapperclassFilterChainclassdoFinally()(TryCatchFinally)doGet()encodeRedirectURL,usinginFirstServletclass(example)outputdisplayedinbrowserHttpServletclassincludingcontentinJavaBean,usingtosendemailPrivacyServletclass(example),includingresourcespecifiedbyinitparameterservletaccessingdatabaseusingJDBCservletmethodtowhichfilterismappedservletusingaJavaBeantohandleemalattachmentsservletusingJavaBeantosendemaildomainattribute(cookies)doPost()FirstServletclass(example)outputdisplayedinbrowserHttpServletclassincludingcontentinPOSTHTTPrequests,respondingtotrackingauser'srefreshcountdoStartTag()2nddoTag()simpletaghandlersdownloadprogress,showingtouserDriverManagerclassDTD[SeeDocumentTypeDefinition]dynamiccontent,combiningmultimediawithinJSPsdynamicallyincludingcontentconfiguringincludedresourceinexternalfile
externalconfigurationfile,usingtoincluderesourceinaJSPimportingaresourceeachtimeservlethandlesarequestincludingcontentfromoutsideacontextinJSPincludingcontentinaJSPforeachrequestincludingXMLfragmentinJSPdocumentresourcesnestedatmultiplelevelsinservletexceptioninformation,displayingfirstinnerincludedservletouterincludingservletrequestattributes,accessbyincludedresourcessecondincludedservletresourcesthatseldomchange,includinginJSPserverperformanceand
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
EAR(EnterpriseApplicationArchive)fileechotask(Ant)EIS(EnterpriseInformationSystems)ejb-jar.xmlfilecontentsof,displayingEJBs(EnterpriseJavaBeans)accessinganEJBonWebLogicfromaservlet,usingJNDIdeploymentdescriptor(ejb-jar.xml)deploymentdescriptor,vendor-specificservlet(example)statelesssessionbean(example)EL[SeeExpressionLanguage]elements,XMLAnttasksbuild.xmlfile(Ant)Contextelement(Tomcatserver.xmlfile)inweb.xmlfileforservletAPI2.3inweb.xmlfileforservletAPI2.4orderinvalidXMLfileemailaccessingfromaservletaccessingfromaservletusingaJavaBeanaddingattachmentstoanemailinaservletJavaBeansActivationFramework(JAF)JavaMailAPIplacingclassesrelatedtoonclasspathreadingreceivedemailheadersfromaservletreceivedinaservlet,handlingattachmentsfromsendingfromaservletservletinteractionwithmailserversendingfromaservletusingaJavaBeanEmailBean(example)servletusingJavaBeantosendemailsettingemailpartswithbeanmethodsemailaddresses,validatinginforminputwithJavaScriptembedtags(HTML)2ndautomaticHTMLfilegenerationbyFlashproducedbyHTMLConverterencodeRedirectURL(HttpServletResponse)encodeURL()(HttpServletResponse)EnterpriseApplicationArchive(EAR)fileEnterpriseInformationSystems(EIS)EnterpriseJavaBeans[SeeEJBs]entitycodesforspecialcharacters2ndc:outtag,escapedcharacterslistingofentrySet()(Map)2ndEnumerationtypeERRORlevelloggingerror-pageconfigurationauthenticationfailurepage(/loginError.html)elementinweb.xmlforIOExceptions
inweb.xml,exampleofoverriddenbypagedirectivedeclarationerror-pageelement(web.xml)2ndconfiguringerrorpagesErrorDataclasserrorPageattribute(pagedirective)escapedcharacters,c:outtagescapeXmlattribute(c:outtag)EventObjectclassexamplecodefromthisbook,useofexceptionimplicitobjectexception-typeelement(web.xml)exceptionsincustomtagclasshandlinginwebapplicationscreatingerror-handlingJSPdeclaringexceptionhandlersinweb.xmldeclaringexception-handlingJSPforotherJSPsexception-handlingservletsendingerrorfromaJSPsendingerrorfromaservletthrownduringincludeoperationsexcludeelement(Ant)executeUpdate()(CallableStatement)expirationforcookiessettingsettingwithjsp:setPropertyexpiresattribute(cookies)explodeddirectoryformatExpressionLanguage(EL)callingLoginBean'sgetLoginSuccess()clientlocales,preferredandless-preferredcookieimplicitobjectcookies,accessingwithcreatinghperlinksinURLrewritingcreationtimeforsessions,fetchingdereferencingofvariableandpropertyvaluesfunctionthatcallsastoredprocedureJavaclassthatimplementsfunctionJSP,useinTLDfileforconfiguringfunctionfunctionsinJSPerrorpageinJSPusedaserrorpageintemplatetext(JSP2.0specification)JavaBeanproperties,accessingwithJSPexamplepage,useinJSTLandmapentrykey/valuepairsrequestheaders,accessingwithvalueofaparticularheaderrequestparameters,accessing2ndscopedattributes,accessingscopedvariables,accessingwithtemplatetext,usingELexpressionsdirectlyinURLforJavaScriptwindowinaJSP,gettingfromacontextparameter
ExtensibleStylesheetLanguage(XSL)ExtensibleStylesheetLanguageTransformations(XSLT)extensionmappingURLpatternsassociatingfilterwithany.jspfilemappingallreferencestoJSPpagestoasingleservletmappingstaticcontenttoaservletexternal-includeproperty
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
FATALlevelloggingfileextensionsassociatingMIMEtypeswithfileuploads[Seeuploadingfiles]FileDataSourceclassFilerConfigclassgetInitParameter()FileRenamePolicyinterfacefilesetelements(Ant)2ndnestedwithinjartasknestingmultipleinpathelementfilterelements(web.xml)2ndinit-paramchildelementFilterinterfaceactionsthatfilterscanundertakefilter-mappingelements(web.xml)2ndapplyingfiltertoaservletusingaRequestDispatcherchangingorderofmappingmultiplefilterstoaservleturl-patternnestedelementFilterChainclassdoFilter()2nd3rdFilterConfigclassgetInitParameterNames()filteringblockingIPaddresseswithchangingorderinwhichfiltersareappliedtoservletsconfiguringinitializationparametersforafilterfilterconfigurationinweb.xmlfile(servletAPI2.3)HTTPresponsesinterceptingandreadingforminputJNDIobject,accessingfromaJSPsettingobjectassessionattributemappingafiltertoaJSPmappingafiltertoaservletfilterthatlogssomeinformationmappingmultiplefilterstoaservletmonitoringsessionattributesMultipartFilterclassoptionallyblockingarequestwithafilterpassingJNDIobjecttoJSPonWebLogicrequestheaders,alteringusingfilterswithRequestDispatcherobjectsvalidatingforminputwithafilterFlashfilesembeddinginaservletHTMLtemplateforembeddinginaJSPautomaticallygeneratingwritingfmt:formatDatetagcurrentlocale,usingtoformatdatesandnumbersfmt:formatNumbertag
currentlocale,usingtoformatnumbersdisplayingcurrencyvalueforalocaledisplayingnumbersaspercentagesfmt:messagetagsfmt:setBundletagfmt:setLocaletagfn:contains()fn:length()fn:split()fn:toUpperCase()Folderclass2ndfootersegmentincludedinJSPwithjsp:includeactionformtags(HTML)actionattributeaction,methodandenctypeattributesforfileuploadsform-basedauthenticationformforusewithloggingoutuseronsystemthatusesform-login-configelementformat()DateFormatclassNumberFormatclass2ndformattingtags(JSTL)displayingdateinJSPforuserlocaledisplayingtextinJSPforrequestlocaleFORWARDvalue(dispatcherelements)forward()(RequestDispatcher)forwardingrequestscontrollerservletforwardingwithRequestDispatcher.forward()withforward()(RequestDispatcher)withgetNamedDispatcher()(ServletContext)initiatingafilterforbyobjectsimplementingRequestDispatcherinterface,withouttriggeringsecurityconstraintsfragments,JSPincludedinaservletbyusingRequestDispatchernowreferredtoasJSPsegmentsFrontControllerdesignpattern(SunMicrosystems)fullyqualifiedclassnamesinvokingregisteredservletthroughlistenerclassinlistenerclasselementobjectattributenamesandfunctioncallsembeddedinJSPcodewithJSTL2ndfunctiontagfunctionsExpressionLanguage,callingstoredprocedureJavaclassthatimplementsfunctionJSP,useinTLDfileforconfiguringfunctionJavaScriptJSTLlistingof,withpurposeofeachusinginJSPs
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
GETrequestssecurityconstraintsonservletresponsetogetAllHeaders()MessageclassPartinterfacegetAttribute()(ServletContext)getBundle()(ResourceBundle)2ndgetConnection()(DataSource)2ndgetContent()(Message)getContextPath()(HttpServletRequest)getCookies()(HttpServletRequest)2ndgetCurrencyInstance()(NumberFormat)getDateTimeInstance()(DateFormat)getDisplayName()(Locale)getFilesystemName(MultipartRequest)getFrom()(Message)getHeader()HttpServletRequestclassPartinterfacegetHeaderNames()(HttpServletRequest)getID()(HttpSession)getInitParameter()(FilterConfig)getInitParameterNames()(FilterConfig)getInputStream()PageDataclassPartinterfacegetInputStream()(PageData)getJspBody()(SimpleTagSupport)getJspContext()(SimpleTagSupport)getLastAccessedTime()(HttpSession)getLocale()(ServletRequest)getLocales()getLoginSuccess()LoginBeanclass(example)getMaxInactiveInterval()(HttpSession)getMetaData()ConnectionclassResultSetclassgetName()Cookieclass2ndHeaderclassgetNamedDispatcher()(ServletContext)getParameter()(ServletRequest)2ndhandlingposteddatagetParameterMap()HttpServletRequestclassServletRequestclass2ndhandlingposteddatagetParameterNames()(ServletRequest)getParameterValues()(ServletRequest)getPath()(Cookie)
getPercentInstance()(NumberFormat)getQueryStringHttpServletRequestclassgetQueryString()requestwrappersthatoverridegetRealPath()(ServletContext)getRemoteAddr()(HttpServletRequest)getRemoteUser()(HttpServletRequest)getRequestDispatcher()(ServletRequest)getRequestURI()(HttpServletRequest)getRequestURL()(HttpServletRequest)getResultElements()(GoogleSearchResult)getRows()(Result)getSearchResults()2ndgetServletContext()getServletRequest()(ServletRequestEvent)getSession()HttpServletRequestclass2nd3rd4thHttpSessionBindingEventclassHttpSessionEventclassgetSnippet()(GoogleSearchResultElement)getSource()(EventObject)getSummary()(GoogleSearchResultElement)getTitle()(GoogleSearchResultElement)getTransactionIsolation()(Connection)2nd3rdgetURL()(GoogleSearchResultElement)getValue()Cookieclass2ndHeaderclassHttpSessionBindingEventclassglobal.propertiesfile(Ant)exampleof2ndGoogleWebServicesconnectingtowithaJSPconnectingtowithaservletcreatingaJavaBeantoconnectwithoptionsforsearches,settingsettingupwithGoogleSearchclass(example)GoogleSearchResultclassGoogleSearchResultElementclass
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
handleMessages()EmailBeanclass(example)MailAccessorclass(example)handleStartTag()harvestingWebinformationcreatingJavaBeanasHTMLparserJavaBeanforHTMLparsingusinginaJSPusinginaservletparsingHTMLpagewithjavax.swing.textsubpackagescallbackclass(example)usingaservletHashtableclassHeaderclassheaderimplicitobject2ndheadersegmentincludedinJSPwithjsp:includeactionheadersemail,readingfromaservletHTTP[Seerequestheadersresponseheaders]headerValuesimplicitobjectheadingattribute(customtag)2ndhomeandlocalhomeinterfaces(EJBonWebLogic)Hostelement(Tomcatserver.xmlfile)2ndhrefattributeHTMLcodeforJSPthathandlesHTTPrequestsconvertingXMLfileintowithXSLstylesheeterrorpagesenttoclientfileuploadpage,preparingcomponenttoreceivefileandstoreinlocaldirectoryformtag2ndonSubmiteventhandlerheadtaginputtagJavaBeanforparsingcreatingusinginaJSPusinginaservletparsingAPIclasses,useinservletsrcattributeofscripttag,usingtoimportJavaScriptmoduletemplateforembeddingFlashfilesgeneratingautomaticallytemplateforincludingFlashfileswritingHTMLConverter(JavaPlug-in)HTMLformsaddingparameterstoquerystringusingaJSPusingaservletinterceptingandreadingforminputwithafilterpostingsubmitteddatafromaJSPservlethandlingof
FirstServletclass(example)servlet,acceptingAmazonsearchtermsettingpropertesofJavaBeantovaluesenteredinsettingscopedattributeinaJSPtovalueofaformparametersubmissiontoserver-sideprogramviaPOSTmethodvalidatinginputwithafilterfilterthatchecksvalues(example)JSPthatcontainsaform(example)HTMLtagsapplettagembedtag2ndgeneratedwithJavaPlug-inHTMLConverterforloadingappletsobjecttag2ndHTMLEditorKitclassHTTPdevelopingJSPforhandlingofrequestsGETmethod[SeeGETrequests]POSTmethod[SeePOSTrequests]requestheaders[Seerequestheaders]requestsforfileuploadingresponseheaders[Seeresponseheaders]secureconnections[SeeSecureSocketsLayer]securityconstraintsonmethodsXML-basedSOAPmessagesonHTTPresponsecodes403or404,handlingbywebcontainer500,returnedbywebcontainerintparameterofsendError()http-methodelementssecurityconstraintsforHttpClient(JakartaCommons)automatingdatapostingfromservlettootherprogramsdownloadingservletusingtopostdatatoaJSPuseinJavaBeanthatpostsdatafromJSPpagehttps://,URLsthatstartwithHttpServletclassinit(),includingcontentinservice()HttpServletRequestclasscheckingsessionexistencegetContextPath()getCookies()2ndgetHeader()getHeaderNames()getParameterMap()getQueryString()getRemoteAddr()getRemoteUser()getRequestURI()getRequestURL()getSession()2nd3rdisUserInRole()HttpServletRequestobjectsHttpServletRequestWrapperclassHttpServletResponseclass
addCookie()encodeRedirectURL()encodeURL()Refreshresponseheader,addingsendError()2ndsendRedirect()2ndHttpServletResponseobjectsHttpServletResponseWrapperclass,forusewithafilter(example)HttpSessionclassgetId()getLastAccessedTime()getMaxInactiveInterval()invalidate()removeAttribute()setAttribute()setMaxInactiveInterval()2ndHttpSessionActivationListenerinterfaceHttpSessionAttributeListenerinterfaceHttpSessionBindingEventclassgetSession()getValue()HttpSessionBindingListenerinterfaceHttpSessionEventclass,getSession()HttpSessionListenerinterfacenotificationofsessioncreationanddestructionsessionCreated()andsessionDestroyed()
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
i18n[Seeinternationalization]if/then/elsestatementsIllegalStateException,handlinginwebapplicationsimgtag(HTML)implicitobjects2nd3rdimplicitobjects,JSPsapplicationexceptionpageContext2ndresponsesessionimplicitobjects,JSTLapplicationScopecookie2nd3rdheader2ndheaderValuesinitParam2ndparam2nd3rd4threquestScope2ndsessionScope2nd3rdimportcustomactionincludedirectivechangesmadetoincludedpage,reflectioninincludingpageinJSPdocument,expansionbyXMLviewincludingseldomchangingresourceinaJSPincludingXMLfragmentinJSPdocumentjsp:includeactionvs.2ndruleofthumbforusingincludeelement(Ant)includemechanismsfordynamiccontentconfiguringincludedresourceinexternalfileexternalconfigurationfile,usingtoincluderesourceinaJSPimportingaresourceeachtimeservlethandlesarequestincludingcontentfromoutsideacontextinJSPincludingcontentinaJSPforeachrequestincludingXMLfragmentinJSPdocumentresourcesnestedatmultiplelevelsinservletexceptioninformation,displayingfirstinnerincludedservletouterincludingservletrequestattributes,accessbyincludedresourcessecondincludedservletresourcesthatseldomchange,includinginJSPINCLUDEvalue(dispatcherelements)include()(RequestDispatcher)2ndembeddingFlashinaservletincludingJavaScriptCreateWindowfunctioninaservletincludingtop-levelservletfileservletimportingJavaScriptfilevalidatingJavaScript,includinginservletincludesattribute(Antjartask)IncludeServletclass(example)
INFOlevellogginginheritancestructureinlog4j2nd3rdinittarget(Ant,build.xmlfile)2ndinit-paramelement(web.xml)specifyingincludingresourcewithtimeoutvalueforservlet,configuringURLforloadingnewwindowcreatedbyJavaScriptfunctioninaservletinitialcontextInitialContextclass2ndclose()lookup()2ndinitializationparametersconfiguringforafilterservlet,registerednameandinitialize()(LoginModule)initParamimplicitJSTLobject2ndinputtags(HTML)multiplefileuploadstype,name,andacceptattributes,forfileuploadsInputStream,XMLviewofJSPpagereturnedas2ndINSERTstatement(SQL),executinginJSPinatransactioninternalresourcesfromwebapplication,viewinginternationalization2ndclientlocale,detectinginaJSPclientlocale,detectinginaservletcreatingResourceBundleasaJavaclassdefinitionofformattingcurrenciesinaJSPformattingcurrenciesinaservletformattingdatesinaJSPformattingdatesinaservletformattingpercentagesinaJSPinaservletlocalizationcontext,settinginweb.xmlResourceBundleaspropertiesfile,creatingResourceBundle,usinginaJSPResourceBundle,usinginaservletInternetExplorerembeddingFlashfilesinwebcomponentsHTMLobjecttag,loadingappletwithlanguagepreference,setting(v.5.5)InternetAddressclass2ndinvalidate()(HttpSession)invoke()(JspFragment)invokerservletsinvokingservletsregisteredinweb.xmloverridingtodirectallrequeststocontrollerservletIOExceptionclass2ndJSPthatthrows(example)webapplications,handlinginIPaddresses,blockingrequestsfromwithafilteris-xmlelementisErrorPageattribute(pagedirective)ISO(InternationalStandardsOrganization)countrycodes2nd
languagecodesisolationlevelsfortransactionsinsql:transactiontagisUserInRole()(HttpServletRequest)iteratingovercollectionsofdatac:forEachtag,iteratingoverarrayiteratingposteddatawithJSTLIteratorclassnext()iterator()(Set)
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
J2EE(Java2EnterpriseEdition)CoreBlueprintswebpageEJBinbusinesstierJavaMailandJavaBeansActivationFramework(JAF)J2SE(Java2StandardEdition)JAAS(JavaAuthenticationandAuthorizationService)authenticatingservletclientsconfigurationfile,creatingflagvalues,listingoflocationoffileLoginModuleclassCallbackHandlerforexamplecodeonlinedocumentationusinginaJSPJAF(JavaBeansActivationFramework)2ndJakartaCommonsHttpClient[SeeHttpClient]JakartaTomcat[SeeTomcat]JAR(JavaARchive)filescreatingwithAntforJakartaCommonsHttpClientincludingTomcatJARfilesinAntclasspathlog4j.jarmail.jarandactivation.jarpackagingJSPtagfileinpackagingtaglibraryinSunMicrosystemsspecificationforWEB-INF/libdirectory,storageinjartask(Ant)2ndbasedirattributedestfileattributefileset(nested)elementincludesattributemanifestfile,creatingjartoolplacingtaglibraryinaJARfilejartool,creatingWARfileswithJasper(TomcatJSPcontainer)jasper-runtime.jarJASPER_HOMEenvironmentvariableJava2EnterpriseEdition[SeeJ2EE]JavaAPIforXMLProcessing(JAXP)2nd3rdJavaAuthenticationandAuthorizationService[SeeJAAS]javacommand-linetool,settinguserclasspathJavaDatabaseConnectivity[SeeJDBC]JavaDevelopmentKit(JDK)JavaNamingandDirectoryInterface[SeeJNDI]JavaPlug-indifferentinstalledversions,causingproblemsloadingappletsHTMLConverter,embeddingappletinaJSPJavaRuntimeEnvironment(JRE)applets,runningin
executingappletwithJavaPlug-inJavaVirtualMachine(JVM),servletsandJavaWebServicesDeveloperPack(WSDP)JavaWebServicesDeveloperPack,downloadingJAXPJava-basedwebapplicationsJAVA_HOMEenvironmentvariablesettinginAntinstallationJavaBeansaccessingemailfromaservletconfiguringasaJNDIobjectwithTomcatcookies,creatingCookieBean(example)creatingaswebpageparsercreatingtosearchAmazoncreatingtosearchGooglewebdatabasecustomizingresponsessenttoclientsemailattachments,handling(example)file-uploading(example)GooglesearchutilityclassJAASAPI,usingforauthenticationJSPdata,postingdynamicallytoanotherserver-sideprocessJSPusingtosearchgoogle.compropertiesaccessingwithELsettinginaJSPsendingemailfromaservletEmailBean(example)servletusingJavaBeantosendemailsettingofemailpartswithbeanmethodsservletusingtoconnecttoAmazonWebServicesasTomcatJNDIresourceaccessingfromaservletwebpageparserusinginaJSPusinginaservletJavaBeansActivationFramework(JAF)2nd3rdjavaccompilerbuilt-in,withSunMicrosystemsJDKjavactask(Ant)classpathelementnestedinsideofcompilingapplicationservletsintobuilddirectoryJavaMailfetchingemailmessageslistingemailheaderspropertiessetforSessionJNDIobjectSession,Store,Folder,andMessageclassesJavaScriptcreatingnewbrowserwindowinaJSPcreatingnewbrowserwindowinaservletincludingJavaScriptmodulesinaJSPincludingJavaScriptmodulesinaservletvalidatingforminputinaservletvalidatingformvaluesinaJSPJavaServerPages[SeeJSPs]JavaServerPagesStandardTagLibrary(seeJSTL)javaxsub-packagesforBEAWebLogic
javax.mailpackagejavax.mail.internetpackagejavax.namingpackage2ndjavax.servlet.jsp.tagextpackagejavax.sqlpackageJDBC(JavaDatabaseConnectivity)accessingdatabasefromservletusingJDBCcallingstoredprocedurefromaservletwithCallableStatementConnectionobjectsdatabasedriverandstoragelocation2ndDriverManagerclassjavax.sql.DataSourceobjectcreatingonWebLogiconWebLogic,usinginaJSPSQLJSTLtag,usingwithOracleclasses12.zipdriverResultSet,convertingtoResultobjectResultSetMetaDatainterfacespecification,addressfordownloadingtransactionAPIJDK(JavaDevelopmentKit)version1.1,AntsupportofJNDI(JavaNamingandDirectoryInterface)2ndconfiguringJNDIobjectinTomcatconfiguringJNDIresourceinWebLogiclookup,usingtoaccessWebLogicDataSourceTomcatJNDIresourceaccessingfromaJSPaccessingfromaservletusingAPIclassestoobtainDataSourceWebLogicJNDIresourceaccessingfromaaJSPaccessingfromaservletWebLogicJNDItreeaccessinganEJBwithforaDataSourceviewingJRE(JavaRuntimeEnvironment)applets,runninginexecutingappletwithJavaPlug-injsp-property-groupelement2ndjsp:directive.includeelementjsp:directive.pageelementaddedtoJSPdocumentbyXMLviewjsp:doBodyaction2ndjsp:forwardactionjsp:getPropertyactionjsp:idattributeforXMLelementsinJSPdocumentjsp:includeactionexternalconfigurationfile,usingtoincluderesourceinaJSPimmediatereflectionofchangestoincludedfilesincludedirectivevs.2ndruleofthumbforusingincludingresourceinJSPeachtimeitreceivesrequestincludingXMLfragmentinJSPdocumentjsp:paramaction
jsp:paramelements,providingembeddedappletswithparameterandvaluepairsjsp:pluginactionembeddingappletinaJSPHTMLtagsgeneratedforloadingJavaappletjsp:rootelement2ndaddedbyXMLviewtoJSPdocumentjsp:setPropertyactioncookieproperties,settingcookievalue,settingsettingdirectorynameforsavinguploadedfilesettingJavaBeanpropertytosubmittedformvaluejsp:textelementjsp:useBeanaction2nd3rd4th5thcookie-creatingbean,usinginJSPidattributeinstantiatingfile-uploadingbeaninaJSPuseinsettingbeanpropertytosubmittedformvaluejsp_precompileparameterjspc(weblogic.jspcprecompilationtool)JspCcommand-linetool(Tomcat)JspContextclassJspFragmentinterface.jspffilesvs.JSPs(JavaServerPages)applicationserversassoftwarehostsforasXMLdocumentscreatingfromscratchasJSPdocumentcreatingJSP-typeURLforaservletcustomXMLtags[Seecustomtagstags]deploying[SeedeployingservletsandJSPs]2nd[SeedeployingservletsandJSPs]fragmentsgeneratingXMLviewfromimplementationclasspackaginginWARfilesprecompiled,mappingtopageimplementationclassprecompilinginTomcatinWebLogicprecompilationprotocol,usingrequestattributes,accessbyincludedresourceswritingasXMLfilesbasicstepsinviewingoutputinbrowserJspWriterclassJSTL(JavaServerPagesStandardTagLibrary)2ndarraysorMaps,usingtoiteratethroughvaluesc:choose,c:when,andc:otherwisetagsc:forEachtag2nd3rd4th5thiteratingposteddatawithc:iftag2ndc:importtag2nd3rd4th5thc:outtag2nd3rd4th5th6thescapedcharactersexceptioninformation,displayingforaJSPsummaryoffunctions
useinaJSP(example)c:paramtagc:settag2nd3rdsummaryoffunctionscookieimplicitobjectcookies,accessingwithELcoretags,usinginaJSPcurrentsessionID,displayingcustomtagsinJSPscreatedasXMLfilesdownloadingandusing1.0referenceimplementation,libdirectorycontentsJSTL1.1taglibdirectivesfordifferentJSTL1.0librariesdownloadingJavaWebServicesDeveloperPackExpressionLanguage(EL)[SeeExpressionLanguage]fmt:formatDatetagfmt:formatNumbertagdisplayingnumbersaspercentagesformattingcurrencyvalueforalocalefmt:messagetagfmt:setBundletagfmt:setLocaletagformattingnumbersaspercentagesformattingsessioncreationandlast-accessedtimesformattingtagsdisplayingtextinJSPforclientlocalefunctionalityoffunctions,usinginJSPsheaderimplicitobjectinJSPerrorpage2ndJavaBeanproperties,accessingwithELJSPusingResultobjectstoredassessionattributelocalizationcontextfortags,settinginweb.xmlrequestheaders,accessingwithELvalueofaparticularheaderrequestparameters,accessingwithELscopedvariables,accessingwithELsessiondate/timesformattedwithSQLtagswithDataSourceconfigurationwithoutDataSourceconfigurationsql:querytag2ndsql:setDataSourcetagsql:transactiontagsql:updatetagurlcustomactionx:outtagx:parsetagx:transformtag2nd3rdXMLandXSLTtags,usingXMLcoretags,usinginaJSPJVM(JavaVirtualMachine),servletsand
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
key/valuepairs(cookies)keystorefilekeytoolutility
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
l10n[Seelocalization]languagecodes(ISO)languageelementlanguagepreference,settinginNetscape7.1last-accessedtimeforsessionstrackingwithJSPstrackingwithservletslayoutsforloggedmessagesininheritedappenderspatternusedforBasicConfiguratorPatternLayoutSimpleLayoutclass,inrootloggermessageslibdirectory2ndinclusionofnesteddirectoriesinWARfilewithAntwartaskJARfiles,storinginlog4j.jarfileTLDsandlibelement(Ant)listenerelement(web.xml)listenersaddinglistenerclasstoataglibraryapplicationeventconfigurationinweb.xmlfile(servletAPI2.3)examiningHTTPrequestswithmonitoringsessionattributesrequests,trackingforawebapplicationservletcontexteventlistener,usinginloggingsessioneventusinginloggingtrackingsessionlifecyclevalidatingforminputwithListResourceBundleclassload-on-startupelement(web.xml)localhomeinterface(EJBonWebLogic)localedefinitionof2nddetectingforclientinaJSPdetectingforclientinaserverdisplayingmessageappropriateforusingJSTLformattingtagsformattingcurrencyvaluesforinaJSPinaservletformattingdatefordisplayinaJSPinaservletpreferredlocalizationdefinitionoflocalizationcontextsettinginweb.xmllocalizerslocationelement(web.xml)
Locationheaderlog()(ServletContext)2nd3rd4th5thlog4jApacheLog4jlibraryconfigurationfileusedbyservletcontextlistenersessioneventlistenerthatusessettinguplog4j.propertiesfileappenderconfigurationspecifyingdifferentnameforLoggerTagclass2ndloggingappendersaddingtoroootloggerfilterthatlogssomeinformation(example)layoutslog4jandservletcontexteventlistener,usinglog4j,usinginaJSPLogFilter(example),mappedtoaservletloggerscreatingyourownandgivingitanappenderusingwithoutconfigurationfilerequestssessioneventlistener,usingsettinguplog4j2ndwithservletthatusesServletContext.log()loggingoutusers,applicationwithform-basedauthenticationlogin()DataSourceLoginModuleclass2ndLoginContextclass2ndLoginModulelogin-configelements(web.xml)auth-methodnestedelementvaluesforusingwithsecurity-constraintelementlogin.htmlpage(example)LoginBeanclass(example)getLoginSuccess()LoginContextclassloginError.htmlpageloginError.jsppageLoginModuleclassexamplecodemethodsvalidatingusernameandpasswordagainstdatabaseinformationlogout()(LoginModule)longdatatypesreturnedbydate-relatedHttpSessionmethods2ndlookup()(InitialContext)2nd
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
MacromediaFlash[SeeFlashfiles]mail[Seeemail]mailserver,interactionwithemail-sendingservletmailsessions2ndservletgettingfromWebLogicJNDImail.jararchivemailDefaults.propertiesfileManagerapplication(Tomcat)onlinedocumentationforStopTaskclassmanifestfileforJARfilesMapobjectsContextObjectclass(example)2ndmethodsaddingkeysandvaluestomapcookieELimplicitobjectEntrysubclass,getKey()andgetValue()entrySet()headerimplicitobject2ndheaderValuesimplicitobjectJSPparameterspassedforpostingtoJavaBeanMessageclassgetAllHeaders()getContent()getFrom()messagestores2ndMessagingExceptionclassMETA-INFdirectory,TLDsinmethodattribute(HTMLformtag)Methodobjectsmethods(JavaBean),namingconventionsforMicrosoftWordfileasemailattachmentsendingasbinarydataMIMEtypesapplication/mswordapplication/pdfassociatingfileextensionswithcommon,listingofMicrosoftWorddocumentMP3filesmultipart/mixedMimeMessageclass2nd3rdMimetypesFileTypeMapclassmodules,JavaScriptexampleoforganizationandstorageofvalidatingforminput(validate.js)MPEGaudiolayer3(MP3)embeddedfileinaJSPsendingaudiofileasmultimedia,embeddinginJSPsembeddingappletwithHTMLConvertertool
embeddingappletwithjsp:pluginembeddingbackgroundsoundtrackinaJSPembeddingFlashinaservletembeddingQuickTimemovieinaJSPembeddingSVGfileinaJSPHTMLtemplateforembeddingFlashfilesgeneratingautomaticallywritingMultipartclassMultipartcontenttypemultipart/form-datacontenttypeMultipartFilterclassMultipartParserclassMultipartRequestclassfile-uploadingJavaBean,useinservletthatuses,creatingMultipurposeInternetMailExtensions[SeeMIMEtypes]MutableAttributeSetclass
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
nameattribute(Antprojectelement)namespacedefinitionofidentifiedbyprefixattributeoftaglibdirectiveforXMLelementsrelatedtoXMLSchemainstancesxmlnsattributeoftaglibelementnamingconventions,log4jnamingservletscreatingmultiplemappingstoaservletcreatingwelcomefilesforwebapplicationinvokingservletwithoutaweb.xmlmappingJSP-typeURLforservletsmappingallrequestsfromawebapplicationtoaservletmappingallrequeststocontrollerwhilepreservingallservletmappingsmappingservlettonameinweb.xmlmappingstaticcontenttoaservletrestrictingrequestsforcertainservletsNetscapedisablingcookiesJavaScript,developers'websitesettinglanguagepreference(v.7.1)next()(Iterator)non-repeatablereadnullrolesecurityroleNumberFormatclassformat()2ndgetCurrencyInstance()getPercentInstance()numbers,formattingwithJSTLtagsfmt:setLocaletag
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
objectattributesforwebapplicationssettingscopewithc:settagobjecttags(HTML)2ndautomaticHTMLfilegenerationbyFlashproducedbyHTMLConverter(example)objectsEJB,factoriesforscopesofonSubmiteventhandler(HTMLformtag)2ndopensourceapplicationsopenConnection()(URL)Oracle8idatabaseservletthatqueriesforaResultSetstoredprocedureaddingrowtotableOraclesequencesorg.apache.jasper.runtimepackageoverwritingacookie
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
packagesfully-qualifiedclassnamesandforservletandutilityclassespageattribute(jsp:include)2ndpagedirectiveerrorPageattributeimportattributeisErrorPageattributeoverridingerror-pageconfigurationpageimplementationobjectpagerelativepathpagescope2ndpageContextimplicitobject2ndPageDataclass,getInputStream()2ndpageEncodingattribute(jspdirective.pageelement)PAM(PluggableAuthenticationModule)paramimplicitobject2nd3rd4thparam-valueelement,alteringtoimportincludedresourceparse()(ParserDelegator)2ndsynchronizationofParserCallbackParserDelegatorclasscallbacks,usingwithparse()2ndsynchronizationofparsingHTMLwithjavax.swing.textsubpackagesJSPsbeforeconversiontopageimpelementationXMLJAXP-compliantparsersx:parsetagPartinterfacegetAllHeaders()getHeader()getInputStream()passwords[Seealsoauthentication]creatingintomcat-users.xmlfileforkeystorefileanddigitalcertificatepathattribute(Contextelement,Tomcat)pathattribute(cookies)accessingvaluesforsettingtonameofcontextpathpathelement(Ant)2nd3rdnestingthreefilesetsinPATHenvironmentvariableAnt/bindirectory,addingtoincludingpathtothebindirectoryofyourJavaSDKinstallationforSunJDKjavaccompilerpathparameterpathscontext-relative
cookie,settingwithjsp:setPropertypage-relativetosavedirectory,forfileuploadservlet2ndservletcreatingforwebapplicationusersdifferencesamongservletenginespatternlanguageforconvertingloggedmessagelayoutsPatternLayoutclass2ndPDF(PortableDocumentFormat)filespercentagesformattinginaJSPformattinginaservletpermissionsforusingcodeexamplesphantomreadPluggableAuthenticationModule(PAM)pop-upwindow,creatingwithJavaScriptfunctioninaservletportnumbers,usedbysecurevs.insecureHTTPconnectionsPortableDocumentFormat(PDF)filesPortableDocumentFormatfiles[SeePDFfiles]POSTrequestsdeliveryofHTMLformdatatoserver-sideprogramviafileuploadsandhandlinginaJSPhandlinginaservletwithServletRequest.getParameter()andgetParameterMap()postingdatafromaJSPpostingdatafromaservlettootherserver-sideprogramsHttpClient,usingtopostdatatoaJSPsecurityconstraintsonPRECLASSPATHenvironmentalvariableprecompilingJSPs2ndinTomcatinWebLogicwithprecompilationprotocolservletmappingspreferredlocaleprefixattribute(taglibdirective)preparetarget(Ant,build.xmlfile)2ndprintffunctioninCPrintWriterclassHTMLpagereturnedbyblockingfilterPrivacyServletclass(example)doGet(),includingresourcespecifiedbyinitparameterJSPfragmentincludedbyprogrammaticsecurityprojectelement(Ant)arrangingtargetelementsinsidepropertiesAntglobal.propertiesfileloadingintobuild.xmlmakingavialabletobuildfileAntpropertytask,importingglobal.propertiesfilebuild.propertiesfile(Ant),forwebapplicationdeploymentcookie,settingexternalfile(include.properties),specifyingresourcetoincludeinJSPjar-nameproperty
JavaBeanaccessingwithELemailpartsstoredassettinginaJSPlog4j.propertiesfilemailDefaults.propertiesfilepassingtoanAntfilecommandline,usingpropertytask,usingpropertiesfileforautomaticallygeneratedXMLviewtagattributesaswl.propertiesfileforWebLogicAntbuildpropertiesfile,ResourceBundleaspropertytask(Ant)2ndPropertyConfiguratorclass
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
querystringsaddingparametertowithaservletaddingparameterstowithaJSPrequest,addingparametertoQuickTimemovie,embeddinginaJSP
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
redirectingrequests(aftercheckingsessionvalidity)referenceimplementationforJSTLrefidattribute(Antclasspathelement)2ndreflection,usinginloggingRefreshheaderJSPthataddstotheresponserefreshingaJSPautomaticallyrefreshingaservletautomaticallyregisterednamesforservletsfilters,mappingtoinvokingregisteredservletswithinvokerservletreloadableattribute(Contextelement,Tomcat)2ndRemoteMethodInvocationregistryremoveAttribute()(HttpSession)renaminguploadedfileswithyourownJavaclassrequestandresponseobjectserrorpageaccesstorequestattributesaccessbyerror-handlingservletaccessbyincludedresourcesinJSPsexceptioninformationfromrequestheadersaccessingwithELimplicitobjectvalueofoneparticularheaderexamininginaJSPexamininginaservletfilter,usingtoalterrequestimplicitobjectrequestparametersaccessingwithELimplicitobject2ndgettingforCallbackHandlerrequestphase(JSPs)requestscope2ndrequest,ServletRequestListenersRequestDispatcherinterface2ndforward()2ndforwardingofHTTPrequestswithouttriggeringsecurityconstraintsforwardingrequeststoservletsundersecurityconstraintsinclude()2ndembeddingFlashinaservletincludingJavaScriptCreateWindowfunctioninaservletincludingtop-levelservletfileincludingvalidatingJavaScriptmoduleinaservletservletimportingJavaScriptfileJSPfragmentincludedinaservletwithRequestDispatcherobjects,usingfilterswithrequestInitialized()requestsblockingfromanIPaddresswithafilteroptionallyblockingwithafilter
requestScopeimplicitJSTLobject2ndResourceelements(server.xml)2nd3rdresource-env-refelement(web.xml)2ndresource-refelement(web.xml)ResourceBundleobjects2ndcreatingasaJavaclasscreatingasapropertyfilegetBundle()2ndlocalizationcontextsetinweb.xmlusinginaJSPusinginaservletResourceParamselements(server.xml)2nd3rdresponsecodes,HTTP[SeeHTTPresponsecodes]responseheadersdefinitionofRefreshJSPs,addingtoresponseimplicitobject(JSP)responsescustomizingwithaJavaBeanfilteringHTTPresponsesrestrictingrequestsforcertainservletsResultinterface2ndResultobjectsconvertingResultSettoResultSetobjectsfindingoutinformationaboutResultSetMetaDatainterfaceservletthatusesResultSupportclasstoResult()rolescheckingforuserswhorequestservletspecifiedinauth-constraintelementrollback()(Connection)2ndrollingfileappenderRollingFileAppenderclassrootelement[Seejsp:rootelement]rootloggeraddinganappenderto
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
save-direlement(web.xml)SAX(SimpleAPIforXML)ScalableVectorGraphics(SVG)file,embeddinginaJSPscopedattributesusingELandc:outtagtogetvalueofscopesboundobjectsforstoredobjectsscrapinginformationfromawebpage[SeeharvestingWebinformation]scriptblocks(JavaScript)scriptletsSDK(SoftwareDevelopmentKit)GoogleWebAPIsSDKPATHenvironmentvariablesecureattribute(cookies)SecureSocketsLayer(SSL)built-insessiontrackingmechanismsettinguponTomcatsecurityconfiguringweb.xmlwithwebapplicationsecurityelementsrelatedto,indeploymentdescriptorsnotusingservletv2.4includingsecurity-relatedcodeinservletsrestrictingrequestsforcertainservletsservletaccess,restrictingtocontrolleronlysecurityrolesnullrole,preventingusermappingtointomcat-users.xmlsecurity-constraintelements(web.xml)auth-constraintnestedelementblockingallrequestsexceptfromRequestDispatcher.forwardexampleofinitiatingauthenticationwithaJSPlogin-configelement,usingwithrestrictingrequestsforcertainservletsservletaccess,restrictingtocontrollerservletonlyspecifyingwebresourcesrequiringauthenticationweb-resource-collectionnestedelementsecurity-roleelements(web.xml)2nd3rdsegments,JSPselectattribute(x:forEach)SELECTstatement(SQL)executinginJSPinatransactionsendingtodatabasewithsql:querytagself-signeddigitalcertificate,creatingforTomcatsend()(Transport)2ndsendError()(HttpServletResponse)2ndsendingnon-HTMLdataaudiofilesPDFfilesviewinginternalresourcesinaservletwordprocessingfilesXMLfilessendRedirect()(HttpServletResponse)2nd
sequences,Oracleserverresponsecodes[SeeHTTPresponsecodes]serverstatuscode403Forbiddenserver.xmlfile(Tomcat)ConnectorelementContextelementResourceandResourceParamselementsservers,applicationservice()(HttpServlet)servletAPI2.3deploymentdescriptorthatconfigureserrorpagessessions,configurationinweb.xmlweb.xmlfile2nd[Seealsoweb.xmlfile]servletAPI2.4filters,usingwithRequestDispatchersweb.xmlfile2nd[Seealsoweb.xmlfile]3rdweb.xml,usewithTomcat5andJSTL1.1servletAPIdocumentationservletcontainersservletelements(web.xml)associatingwithmultipleservlet-mappingelementsgeneratedbyJspC,mappingservletstoload-on-startupnestedelementservletengines,commercialServletinterfaceservlet-classelement(web.xml)servlet-mappingelements(web.xml)associatingmultiplewithoneservletelementcreatingaliastoaservletgeneratedbyJspC,mappingservletstoJSP-styleURLpatterninmappingallrequestsfromwebapplicationtoaservletremovingoralteringanyelementsallowingrequeststobypasscontrollerservletmappingstaticcontenttoaservletremovingoralteringanythatallowrequeststobypasscontrollerservletservletswithout,invokingurl-patternelementWebLogicServer7.0servlet-nameelement(web.xml)*wildcardsymbol,notusedinservlet.jar,inclusioninPRECLASSPATHenvironmentvariableServletConfiginterfaceServletContextattributessettinginJSPssettinginservletsobjectthatservletbindstoServletContextservletthatbindsobjecttoServletContextServletContextclass2ndgetAttribute()getRealPath()log()2nd3rd4th5threturninganulldispatchersetAttribute()2ndServletContextListenerinterfacecontextInitialized()andcontextDestroyed()
ServletExceptionclass2ndServletOutputStreamclassServletRequestinterfacegetLocale()getParameter()getParameter()andgetParameterMap()getParameterMap()getRequestDispatcher()methods,usinginservlet'sdoPostmethodServletRequestEventclass,getServletRequest()ServletRequestListenerclassServletResponseclasschangingresponsewithafiltersetBufferSize()servlets2ndapplicationserversassoftwarehostsforcompiling[Seecompilingservlets]conversionofJSPsintodeploying[SeedeployingservletsandJSPs]deploymentdescriptorforservletAPI2.3deploymentdescriptor,creatingforservletAPI2.4JavaServerPages[SeeJSPs]naming[Seenamingservlets]packaginginWARfileswritingFirstServletclass(example)lifecycle,managementofpackages,creatingforSessionclass2nd3rd4thbindingobjecttoWebLogicJNDIservletgettingSessionobjectfromWebLogicJNDIsessioneventlistenerssessionIDdisplayingwithJSTLtagURLsthatautomaticallyinclude,creatingsessionimplicitobject2ndsessionscope2ndJNDIobjectplacedin,usingafiltersession-configelement(web.xml)2ndsessiontimeoutforallTomcatapplicationssession-timeoutelement(web.xml)sessionCreated()(HttpSessionListener)2nd3rdsessionDestroyed()(HttpSessionListener)2nd3rdsessionDidActivate()(HttpSessionActivationListener)SessionFilterclass(example)sessionscheckingexistenceofinHttpServletRequestconfigurationinweb.xmlfileforservletAPI2.3definitionofinvalidatingtologoutusermonitoringsessionattributeswithafiltermonitoringsessionattributeswithalistenertimeout,settinginallTomcatwebapplicationsinservletcode
inweb.xmltrackinglifecyclewithalistenertrackingsessionactivityinJSPstrackingsessionactivityinservletstrackingwithURLrewritinginaJSPtrackingwithURLrewritinginaservletsessionScopeimplicitJSTLobject2nd3rdsessionWillActivate()(HttpSessionActicationListener)Setclass,iterator()Set-Cookieresponseheader2ndsetAttribute()HttpSessionclassServletContextclasssetAutoCommit()(Connection)setBufferSize()(ServletResponse)setContent()setFrom()setKey()(GoogleSearchsetKey)setMaxAge()(Cookie)callingwithargumentvalueofzerosetMaxInactiveInterval()(HttpSession)2ndsetQuery()setQueryString()(GoogleSearch)setValue()(Cookie)shellscriptsforprecompilingJSPfiles(onUnix)forprecompilingallJSPpagesinapplication(onUnix)Tomcat,shuttingdownshow-propstarget(Ant)SimpleAPIforXML(SAX)SimpleObjectAccessProtocol[SeeSOAP]simpletaghandlercreating(JSP2.0)creatingaTLDforusinginaJSPSimpleLayoutclassmessagesloggedbyrootloggerSimpleTaginterface2ndSimpleTagSupportclass2ndgetJspBody()getJspContext()SOAP(SimpleObjectAccessProtocol)responsefromAmazonbasedonkeywordsearch(example)webservicesbasedon,reasonstousesocketconnectionwithadatabaseserverSoftwareDevelopmentKit(SDK)GoogleWebAPIsPATHenvironmentvariablesoundtrack,embeddinginaJSPSQL(StructuredQueryLanguage)executingseveralstatementsinonetransactionservletusingtransactionJSTLSQLtags2ndwithDataSourceconfigurationSQLJSTLtagwithoutDataSourceconfigurationstoredprocedures
transactions,usingwithJSPsSQLPLUSdatabase,addEventstoredprocedure(example)sql:querytagsendingSQLSELECTstatementtodatabasesql:setDataSourcetagsql:transactiontagsql:updatetagsrcattribute(HTMLscripttag),importingJavaScriptmoduleintoservletsrcdirectorySSL[SeeSecureSocketsLayer]startandstoptasks(Ant,build.xmlfile)startingTomcatfromAntStartTasktaskstatelessSessionbean(EJB)definitionofstaticcontentmappingtoaservletrequestsfor,interceptedbycontrollerservletserverperformanceandstaticmethods,JavamethodimplementingELfunctionforJSPstaticpageformultimediacontentstatuscodes,HTTP[SeeHTTPresponsecodes]status_codeattributestopandstarttasks(Ant,build.xmlfile)stoppingaTomcatapplicationwithAntStopTaskclassStoreclass2nd3rdstoredprocedurescallingfromaJSPcallingfromaservletstructureResults()2ndstylesheets(XSL),integratingintoJSPsSunMicrosystemsFrontControllerdesignpatternJAASdocumentationJARfilespecificationJavaDevelopmentKit(JDK)JavaWSDPdownloadsiteonlinetutorialssampleappletswebservicestutorialthatincludesXPathSVGfile,embeddinginaJSPsynchronizedMap()(Collections)
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
t:toxmlelementtagdirectivetagfilescreatingcustomtagassociatedwith,usingpackaginginaJARpackaginginawebapplicationtaghandlersclassiccreatingcreatingJSP1.2TLDforpackagenameforclassessimplecreatingcreatingTLDforusinginaJSPtaglibrarylistenerclass,addingtopackaginginaJARfilepackaginginawebapplicationTagLibraryDescriptor(TLD)files2ndaddinglistenerelementtoconfiguringanELfunctioncreatingforsimpletaghandlercreatingJSP1.2TLDforclassictaghandlercreatingJSP2.0TLDforclassictaghandlercustomloggertagcustomtaginformation,providingdefinitionofforXMLviewcustomtagplacingintaglibraryJAR'sMETA-INFdirectoryspecifyingvalidatorforurifortaglibraryXMLDTD,useinJSP1.2taglibdirectives2ndforcustomtag,identifyingurifortaglibraryfordifferentJSTL1.0librariesinincludedJSPsegment,foruseofc:outJSTL1.0tagsJSPsegmentcontaining(example)requiredforuseofJSTL1.0coreandSQLlibrariesspecifyingcoretaglibraryfromJSTLuriandprefixvaluestousewithfunctionslibraryuriattributevaluesinJSTL1.1taglibelementversionattributexmlnsattributexmlns:xsiattributexsi:schemaLocationattributeTagLibraryValidatorclassusingXMLviewtovalidatecustomtagsinJSPpagetagscustom[Seealsocustomtags]
customtagsinJSPsdefinitionofincludingtaglibrariesasnamespaceattributesinJSPdocumentspre-builtforJSPs(JSTL)TagSupportclass2ndtargetelements(Ant),groupingoftasksintargets(Ant)inbuild.xml,displayingnamesoftaskdefelement(Ant,buildfile)starttask,definingstoptask,definingtasks(Ant)filesetsgroupof,representedbytargetelementpropertytasktextfiles,JSPswrittenasthreadnameinloggingmessagesThrowableclassThrowableobjectsaccessinginJSPerrorpageassociatedwithexceptions,accessingthrownexceptions,informationaboutinJSPerrorpage2ndtimeoutforsessionssettinginallTomcatwebapplicationssettinginservletcodesettinginweb.xmltimeStyleattribute(fmt:formatDate)TimeZoneIDs,helperclasstodisplayTLD[SeeTagLibraryDescriptorfiles]tldfileextensionTomcatcompilingservletonconfiguringDataSourcetouseinservletcontextelement(conf/server.xml),forJSPcontentimportedfromoutsidecontextcreatingusernamesandpasswordsDataSource,usinginaservletdeployingindividualJSPondeployingindividualservletonAnttool,usingstepsinprocessdeployingservletaspartofContextelementinserver.xmldeployingwebapplicationonAntbuildfile,usingpointingtoexternaldirectorycontainingwebapplicationerrorpagedisplayedbyerrorhandlingservletimplicitmappingtoitsJSPcompilerandexecutionservletfor.jsprequestsincludingJARfilesinAntbuildfileclasspathinitialcontextofbuilt-inJNDIimplementationinvokerservletcommentingoutJasper(JSPcontainer)JNDIobject,configuringJNDIresourceaccessingfromaJSPaccessingfromaservletJSPpageimplementationclass,viewing
JSTL1.1features,usingwithversion5logfilesprecompilingJSPsinsecurity-constraintelementinweb.xml,usingsessiontimeout,settingforallwebapplicationsSSL,setlingupstartingwebapplicationwithAntstoppingwebapplicationwithAnttomcat-users.xmlfileexampleofatypicalfilemanagerrole,usermappingtonullrollsecurityrole,preventingusermappingtousermappingtosecurityrolesusernamesandpasswords,case-sensitivityofusernames,passwords,androlesforauthenticationtoResult()(ResultSupport)2ndToXmlValidatorclasstransactionscreatingwithConnectionmethodsexecutingseveralSQLstatementsinsingletransactionservletthatusestransactionisolationlevelsusingwithJSPstransformingXML,usingJSTLXMLandXSLT-relatedtagstranslationphase(forJSPs)2ndincludingJSPsegmentintoJSPpageTransportclass,send()2ndtry/catchblock,forexceptionsthrownduringincludeoperationsTryCatchFinallyinterfacetutorials,online(SunMicrosystems)
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
unbindingsessionobjects,listeningforundeploytarget(Ant,build.xmlfile)Unixkeytoolutility,creatingdigitalcertificatewithshellscriptforprecompilingallJSPpagesinapplicationshellscriptforprecompilingJSPfilesUnix-basedMacOSX10.2system,PATHvariableforjavacUPDATEstatement(SQL)uploadingfilescom.oreilly.servletclassesforfileuploadsJSP,handlingwithfileuploadingJavaBean,creatingJSPthatuploadsanddisplaysinformationaboutmultiplefileuploads2ndpreparingHTMLpageforcomponenttoreceivefileuploadandstoreinlocaldirectoryrenaminguploadedfileswithyourownJavaclassuriattribute(taglibdirective)JSTL1.1,differentvaluesinURIsmappingurielementsinTLDasspecifiedbytaglibdirectiveinJSPfilesrequest,usebyJSPerrorpageurlcustomactionaddingparameterswithencodeURL()vs.rewritingURLswithURLpatterns*.jspisanextensionmapping/sqlJsp.jsp,initiationofBASICauthenticationforaimingallrequestsatacontrollerservletexactmatchingrequirementforJSP-type,creatingforaservletrestrictinganyrequestsfromreachingspecifiedbysecurity-constraintelementsURLrewriting2ndusinginaJSPusinginaservleturl-patternelement(web.xml)*wildcardcharacterincasesensitivityofmappingallrequestsfromwebapplicationtoaservletmappingfiltertoaJSPURLConnectionclassURLsconnectionto,openingexternalimportingintoJSPwithc:importtaginitiatingAmazonsearchwithinvoker-style,forservletsspecifyingadirectoryonlyforstaticcontent,mappingtoaservletuserclasspath
userroles[Seeroles]User-Agentheaderusersmanagerrole(Tomcat)tomcat-users.xmlfilemappingtosecurityrolesusernames,passwords,androlesin
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
validpartialrequestsValidateHandlerclassvalidatingcustomtagsinJSPpagesforminputfilter,usingforJavaBean,usingJavaScript,usinginaJSP2ndJavaScript,usinginaservlet2ndXMLdocuments,specifyingvalidatorforTLDfilevarattribute(c:forEachtag)variabledirectivevariables(scoped),accessingwithEL2ndvariant(inlocales)versionattributecookiestaglibelementviewerapplicationsforSVGviewinginternalresourcesinaservlet
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
WAR(WebARchive)filescreatingwithAntdeployingwebapplicationas,usingWebLogicAdministrationConsolefindingoutifalreadydeployedonTomcatforservletsandJSPsgeneratingwithAntwartaskopeininginWebLogicBuildertoeditweb.xmlfileviewingcontentsofwartask(Ant)2ndclasses,lib,andfileset(nested)elementsdestfileandwebxmlattributesWARNlevelloggingwebapplicationsconfiguringlog4jmechanismcountingnumberofrequestsforcreatingwelcomefilesfordefinitionofdeployingonTomcatAntbuildfile,usingconfiguringTomcattopointtoapplicationinexternaldirectorydeployingonWebLogicusingAnttoolusingWebLogicAdministrationConsoleusingWebLogicBuilderusingweblogic.Deployercommand-lineutilitydeploymentdescriptor,creatingfordirectorystructure[Seedirectorystructureofwebapplications]Java-basedmappingallrequeststocontrollerservletpackagingJSPtagfileinpackagingtaglibraryinservletcontextinstanceservlet,writingforstartingonTomcatusingAntfilestoppingonTomcatusingAntfileWARfiles[SeeWARfiles]webbrowsers[Seebrowsers]webcomponentswebcontainers2nd[SeealsoTomcat]exceptionhandlinginwebdevelopertasks,recipesinthisbookimplementationwithBEAWebLogicwebdirectory,inclusionofnesteddirectoriesinWARfilewithAntwartaskwebpageforthisbookwebservices[SeealsoAmazonWebServices;GoogleWebServices]2ndAmazonandGoogleAmazon,settingupGoogleWebAPI,settingupSOAP,usingforinformationtransferSOAP-based,reasonstoadoptweb-appelement(web.xml)requiredattributesofservlet2.4deploymentdescriptor
WEB-INFdirectory2ndcontentsofWEB-INF/jspf(optionaldirectory)WEB-INF/tlds(optionaldirectory)web-resource-collectionelements(web.xml)protectedresourcesinsecurity-constraintelementspecifyingsecurityrestraintsweb.xmlfile2nd[Seealsoservlet-mappingelements]BASICauthentication,initiatingwithJSPfilecontentsofcontextparametersave-direlementcontext-paramelement,addingforincludedfileinaJSPcreatingmultiplemappingstoaservletcreatingwithJspCutilityDataSource,configuringindeclaringexceptionhandlersineditingforWebLogictoregisteraservleterror-pageattribute,mappingexceptiontypestoaJSPerror-pageconfigurationfiltersconfiguringinmappedtotheservletpath(example)mappingofmappingtoaJSPform-basedauthentication,settingupform-checkingfilterregisteredandmappedinIOExceptions,elementformanagingIPblockingfilter,mappingofjsp-property-groupelement2ndJSP-typeURLforaservletlistenerelementlisteners[Seealsolisteners]configurationinservletAPI2.3forservletrequests,registeringmappingallreferencestoJSPpagestoasingleservletmappingservlettoanamepreventingrequeststonon-controllerservletsresource-refelementrestrictingrequestsforcertainservletsservletAPI2.3convertingto2.4forJSTL1.1featuresservletAPI2.4usewithTomcat5andJSTL1.1servletelementwithload-on-startupnestedelementservletthatcreatespop-upwindowservletswithoutamappinginsessiontimeoutforallTomcatwebapplicationssessiontimeout,settingviewingwithaservletwebappsfolder(Tomcat)WebLogiccreatingDataSourceonconfiguration,stepsinJNDIlookup,usingtoaccessDataSourceJNDIresourceaccessingfromaJSP
accessingfromaservletconfiguringinJNDItreeaccessinganEJBwithviewingprecompilingJSPsinrecipesforcommontasksservletclassesandjavaxsub-packagesWebLogicServer7.0deployingindividualJSPondeployingindividualservletonAntfile,usingeditingweb.xmltoregisterservletredeployingwebapplicationdeployingwebapplicationonusingAnttoolusingWebLogicAdministrationConsoleusingWebLogicBuilderusingweblogic.Deployercommand-lineutilitysecurityconfigurationinweblogic.xmlweblogic-ejb-jar.xmlfileweblogic.Deployercommand-lineutilityweblogic.jspcutilityweblogic.xmlfile,securityconfigurationinwebxmlattribute(Antwartask)welcomefilesforawebapplicationwelcome-file-listelement(web.xml)wildcardsinURLpatternsoverridingwithspecificmappingswindoidWindowssystemslaunchingWebLogicBuilderlocalvariantforPATHenvironmentvariableforjavaccompiler(onNT)precompilingallJSPpagesinapplicationwithweblogic.jspcshellscriptforrunningJspCwindows,browser[Seebrowserwindows,creatingwithJavaScript]wl.applicationsproperty(Ant,build.propertiesfile)wl.propertiesfile(forWebLogicAntbuildfile)WLCLASSPATHenvironmentvariablewordprocessingfiles,sendingWSDP(WebServicesDeveloperPack)
[TeamLiB]
[TeamLiB][SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]
x:forEachtag2ndx:iftagx:outtagx:parsetagx:transformtagassociatingastylesheetwithanXMLfilexmlattributexsltattributeXerces2XMLparserXMLAntbuildfilecreatingJSPdocumentasXMLfileincludingXMLfragmentinaJSPdocumentJSPdocumentvs.XMLviewJSPsasXMLfiles2ndXMLequivalentsofJSPdirectivesJSTLXMLandXSLTtags,usinginaJSPJSTLXMLcoretags,usinginaJSPsendingXMLfileasbinarydataSOAPmessagesonHTTPTLD(TagLibraryDescriptor)filestransforming(x:transform)webservicesXMLelementsAnttaskscase-sensitivityinelementandattributenamescustomtagsusedinJSPnamespaceforelementsrelatedtoXMLSchemainstancesnamespace,definitionofpathelement,definingAntclasspathXMLparsers,JAXP-compliantXMLSchemainstancesXMLSchemasforJSP2.0TLDinservletAPI2.4web.xmlfileXMLviewautomaticallygeneratingforJSPpagegeneratingfromaJSPpageJSPXMLdocumentvs.xmlnsattribute(taglibelement)xmlns:xsiattribute(taglibelement)XPathxsi:schemaLocationattribute(taglibelement)XSL(ExtensibleStylesheetLanguage)XSLT,convertingXMLtoreadableformat
[TeamLiB]
BroughttoYouby
Likethebook?Buyit!